]> git.proxmox.com Git - mirror_edk2.git/blobdiff - MdeModulePkg/Universal/Variable/EmuRuntimeDxe/EmuVariable.c
update
[mirror_edk2.git] / MdeModulePkg / Universal / Variable / EmuRuntimeDxe / EmuVariable.c
index 158e396963dd837ae393fbd6f60225b38ee656e8..faacd218fd24e42cb242dc724d6f86584b9be20a 100644 (file)
@@ -16,17 +16,92 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
 \r
 #include "Variable.h"\r
 \r
-//\r
-// Don't use module globals after the SetVirtualAddress map is signaled\r
-//\r
+///\r
+/// Don't use module globals after the SetVirtualAddress map is signaled\r
+///\r
 ESAL_VARIABLE_GLOBAL  *mVariableModuleGlobal;\r
 \r
-//\r
-// This is a temperary function which will be removed\r
-// when EfiAcquireLock in UefiLib can handle the\r
-// the call in UEFI Runtimer driver in RT phase.\r
-//\r
-STATIC\r
+VARIABLE_INFO_ENTRY *gVariableInfo = NULL;\r
+\r
+///\r
+/// The size of a 3 character ISO639 language code.\r
+///\r
+#define ISO_639_2_ENTRY_SIZE    3\r
+\r
+/**\r
+  Update the variable region with Variable information. These are the same \r
+  arguments as the EFI Variable services.\r
+\r
+  @param[in] VariableName       Name of variable\r
+\r
+  @param[in] VendorGuid         Guid of variable\r
+\r
+  @param[in] Data               Variable data\r
+\r
+  @param[in] DataSize           Size of data. 0 means delete\r
+\r
+  @param[in] Attributes              Attribues of the variable\r
+\r
+  @param[in] Variable           The variable information which is used to keep track of variable usage.\r
+\r
+  @retval EFI_SUCCESS           The update operation is success.\r
+\r
+  @retval EFI_OUT_OF_RESOURCES  Variable region is full, can not write other data into this region.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+UpdateVariable (\r
+  IN      CHAR16                 *VariableName,\r
+  IN      EFI_GUID               *VendorGuid,\r
+  IN      VOID                   *Data,\r
+  IN      UINTN                  DataSize,\r
+  IN      UINT32                 Attributes OPTIONAL,\r
+  IN      VARIABLE_POINTER_TRACK *Variable\r
+  );\r
+\r
+/**\r
+  Finds variable in storage blocks of volatile and non-volatile storage areas.\r
+\r
+  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
+\r
+  @param  VariableName                Name of the variable to be found.\r
+  @param  VendorGuid                  Vendor GUID to be found.\r
+  @param  PtrTrack                    VARIABLE_POINTER_TRACK structure for output,\r
+                                      including the range searched and the target position.\r
+  @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
+\r
+  @retval EFI_INVALID_PARAMETER       If VariableName is not an empty string, while\r
+                                      VendorGuid is NULL.\r
+  @retval EFI_SUCCESS                 Variable successfully found.\r
+  @retval EFI_NOT_FOUND               Variable not found.\r
+\r
+**/\r
+EFI_STATUS\r
+FindVariable (\r
+  IN  CHAR16                  *VariableName,\r
+  IN  EFI_GUID                *VendorGuid,\r
+  OUT VARIABLE_POINTER_TRACK  *PtrTrack,\r
+  IN  VARIABLE_GLOBAL         *Global\r
+  );\r
+\r
+/**\r
+  Acquires lock only at boot time. Simply returns at runtime.\r
+\r
+  This is a temperary function which will be removed when\r
+  EfiAcquireLock() in UefiLib can handle the call in UEFI\r
+  Runtimer driver in RT phase.\r
+  It calls EfiAcquireLock() at boot time, and simply returns\r
+  at runtime\r
+\r
+  @param  Lock         A pointer to the lock to acquire\r
+\r
+**/\r
 VOID\r
 AcquireLockOnlyAtBootTime (\r
   IN EFI_LOCK  *Lock\r
@@ -37,12 +112,18 @@ AcquireLockOnlyAtBootTime (
   }\r
 }\r
 \r
-//\r
-// This is a temperary function which will be removed\r
-// when EfiAcquireLock in UefiLib can handle the\r
-// the call in UEFI Runtimer driver in RT phase.\r
-//\r
-STATIC\r
+/**\r
+  Releases lock only at boot time. Simply returns at runtime.\r
+\r
+  This is a temperary function which will be removed when\r
+  EfiReleaseLock() in UefiLib can handle the call in UEFI\r
+  Runtimer driver in RT phase.\r
+  It calls EfiReleaseLock() at boot time, and simply returns\r
+  at runtime\r
+\r
+  @param  Lock         A pointer to the lock to release\r
+\r
+**/\r
 VOID\r
 ReleaseLockOnlyAtBootTime (\r
   IN EFI_LOCK  *Lock\r
@@ -53,104 +134,671 @@ ReleaseLockOnlyAtBootTime (
   }\r
 }\r
 \r
-STATIC\r
+/**\r
+  Gets pointer to the variable data.\r
+\r
+  This function gets the pointer to the variable data according\r
+  to the input pointer to the variable header.\r
+\r
+  @param  Variable      Pointer to the variable header.\r
+\r
+  @return Pointer to variable data\r
+\r
+**/\r
 UINT8 *\r
 GetVariableDataPtr (\r
   IN  VARIABLE_HEADER   *Variable\r
   )\r
-/*++\r
-\r
-Routine Description:\r
-\r
-  This code gets the pointer to the variable data.\r
+{\r
+  if (Variable->StartId != VARIABLE_DATA) {\r
+    return NULL;\r
+  }\r
+  //\r
+  // Be careful about pad size for alignment\r
+  //\r
+  return (UINT8 *) ((UINTN) GET_VARIABLE_NAME_PTR (Variable) + Variable->NameSize + GET_PAD_SIZE (Variable->NameSize));\r
+}\r
 \r
-Arguments:\r
+/**\r
+  Gets pointer to header of the next variable.\r
 \r
-  Variable            Pointer to the Variable Header.\r
+  This function gets the pointer to the next variable header according\r
+  to the input point to the variable header.\r
 \r
-Returns:\r
+  @param  Variable      Pointer to header of the next variable\r
 \r
-  UINT8*              Pointer to Variable Data\r
+  @return Pointer to next variable header.\r
 \r
---*/\r
+**/\r
+VARIABLE_HEADER *\r
+GetNextVariablePtr (\r
+  IN  VARIABLE_HEADER   *Variable\r
+  )\r
 {\r
+  VARIABLE_HEADER *VarHeader;\r
+\r
   if (Variable->StartId != VARIABLE_DATA) {\r
     return NULL;\r
   }\r
   //\r
   // Be careful about pad size for alignment\r
   //\r
-  return (UINT8 *) ((UINTN) GET_VARIABLE_NAME_PTR (Variable) + Variable->NameSize + GET_PAD_SIZE (Variable->NameSize));\r
+  VarHeader = (VARIABLE_HEADER *) (GetVariableDataPtr (Variable) + Variable->DataSize + GET_PAD_SIZE (Variable->DataSize));\r
+\r
+  if (VarHeader->StartId != VARIABLE_DATA) {\r
+    return NULL;\r
+  }\r
+\r
+  return VarHeader;\r
 }\r
 \r
-STATIC\r
+/**\r
+  Gets pointer to the end of the variable storage area.\r
+\r
+  This function gets pointer to the end of the variable storage\r
+  area, according to the input variable store header.\r
+\r
+  @param  VolHeader     Pointer to the variale store header\r
+\r
+  @return Pointer to the end of the variable storage area.\r
+\r
+**/\r
 VARIABLE_HEADER *\r
-GetNextVariablePtr (\r
-  IN  VARIABLE_HEADER   *Variable\r
+GetEndPointer (\r
+  IN VARIABLE_STORE_HEADER       *VolHeader\r
   )\r
-/*++\r
+{\r
+  //\r
+  // The end of variable store\r
+  //\r
+  return (VARIABLE_HEADER *) ((UINTN) VolHeader + VolHeader->Size);\r
+}\r
 \r
-Routine Description:\r
+/**\r
+  Routine used to track statistical information about variable usage. \r
+  The data is stored in the EFI system table so it can be accessed later.\r
+  VariableInfo.efi can dump out the table. Only Boot Services variable \r
+  accesses are tracked by this code. The PcdVariableCollectStatistics\r
+  build flag controls if this feature is enabled. \r
+\r
+  A read that hits in the cache will have Read and Cache true for \r
+  the transaction. Data is allocated by this routine, but never\r
+  freed.\r
+\r
+  @param[in] VariableName   Name of the Variable to track\r
+  @param[in] VendorGuid     Guid of the Variable to track\r
+  @param[in] Volatile       TRUE if volatile FALSE if non-volatile\r
+  @param[in] Read           TRUE if GetVariable() was called\r
+  @param[in] Write          TRUE if SetVariable() was called\r
+  @param[in] Delete         TRUE if deleted via SetVariable()\r
+  @param[in] Cache          TRUE for a cache hit.\r
 \r
-  This code gets the pointer to the next variable header.\r
+**/\r
+VOID\r
+UpdateVariableInfo (\r
+  IN  CHAR16                  *VariableName,\r
+  IN  EFI_GUID                *VendorGuid,\r
+  IN  BOOLEAN                 Volatile,\r
+  IN  BOOLEAN                 Read,\r
+  IN  BOOLEAN                 Write,\r
+  IN  BOOLEAN                 Delete,\r
+  IN  BOOLEAN                 Cache\r
+  )\r
+{\r
+  VARIABLE_INFO_ENTRY   *Entry;\r
+\r
+  if (FeaturePcdGet (PcdVariableCollectStatistics)) {\r
+\r
+    if (EfiAtRuntime ()) {\r
+      // Don't collect statistics at runtime\r
+      return;\r
+    }\r
+\r
+    if (gVariableInfo == NULL) {\r
+      //\r
+      // on the first call allocate a entry and place a pointer to it in\r
+      // the EFI System Table\r
+      //\r
+      gVariableInfo = AllocateZeroPool (sizeof (VARIABLE_INFO_ENTRY));\r
+      ASSERT (gVariableInfo != NULL);\r
+\r
+      CopyGuid (&gVariableInfo->VendorGuid, VendorGuid);\r
+      gVariableInfo->Name = AllocatePool (StrLen (VariableName));\r
+      ASSERT (gVariableInfo->Name != NULL);\r
+      StrCpy (gVariableInfo->Name, VariableName);\r
+      gVariableInfo->Volatile = Volatile;\r
+\r
+      gBS->InstallConfigurationTable (&gEfiVariableGuid, gVariableInfo);\r
+    }\r
+\r
+    \r
+    for (Entry = gVariableInfo; Entry != NULL; Entry = Entry->Next) {\r
+      if (CompareGuid (VendorGuid, &Entry->VendorGuid)) {\r
+        if (StrCmp (VariableName, Entry->Name) == 0) {\r
+          if (Read) {\r
+            Entry->ReadCount++;\r
+          }\r
+          if (Write) {\r
+            Entry->WriteCount++;\r
+          }\r
+          if (Delete) {\r
+            Entry->DeleteCount++;\r
+          }\r
+          if (Cache) {\r
+            Entry->CacheCount++;\r
+          }\r
+\r
+          return;\r
+        }\r
+      }\r
 \r
-Arguments:\r
+      if (Entry->Next == NULL) {\r
+        //\r
+        // If the entry is not in the table add it.\r
+        // Next iteration of the loop will fill in the data\r
+        //\r
+        Entry->Next = AllocateZeroPool (sizeof (VARIABLE_INFO_ENTRY));\r
+        ASSERT (Entry->Next != NULL);\r
+\r
+        CopyGuid (&Entry->Next->VendorGuid, VendorGuid);\r
+        Entry->Next->Name = AllocatePool (StrLen (VariableName));\r
+        ASSERT (Entry->Next->Name != NULL);\r
+        StrCpy (Entry->Next->Name, VariableName);\r
+        Entry->Next->Volatile = Volatile;\r
+      }\r
+\r
+    }\r
+  }\r
+}\r
 \r
-  Variable                  Pointer to the Variable Header.\r
+/**\r
+  Get index from supported language codes according to language string.\r
 \r
-Returns:\r
+  This code is used to get corresponding index in supported language codes. It can handle\r
+  RFC3066 and ISO639 language tags.\r
+  In ISO639 language tags, take 3-characters as a delimitation to find matched string and calculate the index.\r
+  In RFC3066 language tags, take semicolon as a delimitation to find matched string and calculate the index.\r
 \r
-  VARIABLE_HEADER*      Pointer to next variable header.\r
+  For example:\r
+    SupportedLang  = "engfraengfra"\r
+    Lang           = "eng"\r
+    Iso639Language = TRUE\r
+  The return value is "0".\r
+  Another example:\r
+    SupportedLang  = "en;fr;en-US;fr-FR"\r
+    Lang           = "fr-FR"\r
+    Iso639Language = FALSE\r
+  The return value is "3".\r
 \r
---*/\r
+  @param  SupportedLang               Platform supported language codes.\r
+  @param  Lang                        Configured language.\r
+  @param  Iso639Language              A bool value to signify if the handler is operated on ISO639 or RFC3066.\r
+\r
+  @retval the index of language in the language codes.\r
+\r
+**/\r
+UINTN\r
+EFIAPI\r
+GetIndexFromSupportedLangCodes(\r
+  IN  CHAR8            *SupportedLang,\r
+  IN  CHAR8            *Lang,\r
+  IN  BOOLEAN          Iso639Language\r
+  ) \r
 {\r
-  VARIABLE_HEADER *VarHeader;\r
+  UINTN    Index;\r
+  UINT32   CompareLength;\r
+  CHAR8    *Supported;\r
+\r
+  Index = 0;\r
+  Supported = SupportedLang;\r
+  if (Iso639Language) {\r
+    CompareLength = 3;\r
+    for (Index = 0; Index < AsciiStrLen (SupportedLang); Index += CompareLength) {\r
+      if (AsciiStrnCmp (Lang, SupportedLang + Index, CompareLength) == 0) {\r
+        //\r
+        // Successfully find the index of Lang string in SupportedLang string.\r
+        //\r
+        Index = Index / CompareLength;\r
+        return Index;\r
+      }\r
+    }\r
+    ASSERT (FALSE);\r
+    return 0;\r
+  } else {\r
+    //\r
+    // Compare RFC3066 language code\r
+    //\r
+    while (*Supported != '\0') {\r
+      //\r
+      // take semicolon as delimitation, sequentially traverse supported language codes.\r
+      //\r
+      for (CompareLength = 0; *Supported != ';' && *Supported != '\0'; CompareLength++) {\r
+        Supported++;\r
+      }\r
+      if (AsciiStrnCmp (Lang, Supported - CompareLength, CompareLength) == 0) {\r
+        //\r
+        // Successfully find the index of Lang string in SupportedLang string.\r
+        //\r
+        return Index;\r
+      }\r
+      Index++;\r
+    }\r
+    ASSERT (FALSE);\r
+    return 0;\r
+  }\r
+}\r
 \r
-  if (Variable->StartId != VARIABLE_DATA) {\r
-    return NULL;\r
+/**\r
+  Get language string from supported language codes according to index.\r
+\r
+  This code is used to get corresponding language string in supported language codes. It can handle\r
+  RFC3066 and ISO639 language tags.\r
+  In ISO639 language tags, take 3-characters as a delimitation. Find language string according to the index.\r
+  In RFC3066 language tags, take semicolon as a delimitation. Find language string according to the index.\r
+\r
+  For example:\r
+    SupportedLang  = "engfraengfra"\r
+    Index          = "1"\r
+    Iso639Language = TRUE\r
+  The return value is "fra".\r
+  Another example:\r
+    SupportedLang  = "en;fr;en-US;fr-FR"\r
+    Index          = "1"\r
+    Iso639Language = FALSE\r
+  The return value is "fr".\r
+\r
+  @param  SupportedLang               Platform supported language codes.\r
+  @param  Index                       the index in supported language codes.\r
+  @param  Iso639Language              A bool value to signify if the handler is operated on ISO639 or RFC3066.\r
+\r
+  @retval the language string in the language codes.\r
+\r
+**/\r
+CHAR8 *\r
+EFIAPI\r
+GetLangFromSupportedLangCodes (\r
+  IN  CHAR8            *SupportedLang,\r
+  IN  UINTN            Index,\r
+  IN  BOOLEAN          Iso639Language\r
+)\r
+{\r
+  UINTN    SubIndex;\r
+  UINT32   CompareLength;\r
+  CHAR8    *Supported;\r
+\r
+  SubIndex  = 0;\r
+  Supported = SupportedLang;\r
+  if (Iso639Language) {\r
+    //\r
+    // according to the index of Lang string in SupportedLang string to get the language.\r
+    // As this code will be invoked in RUNTIME, therefore there is not memory allocate/free operation.\r
+    // In driver entry, it pre-allocates a runtime attribute memory to accommodate this string.\r
+    //\r
+    CompareLength = 3;\r
+    SetMem (mVariableModuleGlobal->Lang, sizeof(mVariableModuleGlobal->Lang), 0);\r
+    return CopyMem (mVariableModuleGlobal->Lang, SupportedLang + Index * CompareLength, CompareLength);\r
+      \r
+  } else {\r
+    while (TRUE) {\r
+      //\r
+      // take semicolon as delimitation, sequentially traverse supported language codes.\r
+      //\r
+      for (CompareLength = 0; *Supported != ';' && *Supported != '\0'; CompareLength++) {\r
+        Supported++;\r
+      }\r
+      if ((*Supported == '\0') && (SubIndex != Index)) {\r
+        //\r
+        // Have completed the traverse, but not find corrsponding string.\r
+        // This case is not allowed to happen.\r
+        //\r
+        ASSERT(FALSE);\r
+        return NULL;\r
+      }\r
+      if (SubIndex == Index) {\r
+        //\r
+        // according to the index of Lang string in SupportedLang string to get the language.\r
+        // As this code will be invoked in RUNTIME, therefore there is not memory allocate/free operation.\r
+        // In driver entry, it pre-allocates a runtime attribute memory to accommodate this string.\r
+        //\r
+        SetMem (mVariableModuleGlobal->PlatformLang, sizeof (mVariableModuleGlobal->PlatformLang), 0);\r
+        return CopyMem (mVariableModuleGlobal->PlatformLang, Supported - CompareLength, CompareLength);\r
+      }\r
+      SubIndex++;                       \r
+    }\r
   }\r
+}\r
+\r
+/**\r
+  Hook the operations in PlatformLangCodes, LangCodes, PlatformLang and Lang.\r
+\r
+  When setting Lang/LangCodes, simultaneously update PlatformLang/PlatformLangCodes.\r
+\r
+  According to UEFI spec, PlatformLangCodes/LangCodes are only set once in firmware initialization,\r
+  and are read-only. Therefore, in variable driver, only store the original value for other use.\r
+\r
+  @param[in] VariableName       Name of variable\r
+\r
+  @param[in] Data               Variable data\r
+\r
+  @param[in] DataSize           Size of data. 0 means delete\r
+\r
+  @retval EFI_SUCCESS  auto update operation is successful.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+AutoUpdateLangVariable(\r
+  IN  CHAR16             *VariableName,\r
+  IN  VOID               *Data,\r
+  IN  UINTN              DataSize\r
+  )\r
+{\r
+  EFI_STATUS     Status;\r
+  CHAR8          *BestPlatformLang;\r
+  CHAR8          *BestLang;\r
+  UINTN          Index;\r
+  UINT32         Attributes;\r
+  VARIABLE_POINTER_TRACK Variable;\r
+\r
   //\r
-  // Be careful about pad size for alignment\r
+  // According to UEFI spec, "Lang" and "PlatformLang" is NV|BS|RT attributions.\r
+  //\r
+  Attributes = EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS;\r
+\r
+  if (StrCmp (VariableName, L"PlatformLangCodes") == 0) {\r
+    //\r
+    // According to UEFI spec, PlatformLangCodes is only set once in firmware initialization, and is read-only\r
+    // Therefore, in variable driver, only store the original value for other use.\r
+    //\r
+    AsciiStrnCpy (mVariableModuleGlobal->PlatformLangCodes, Data, DataSize);\r
+  } else if (StrCmp (VariableName, L"LangCodes") == 0) {\r
+    //\r
+    // According to UEFI spec, LangCodes is only set once in firmware initialization, and is read-only\r
+    // Therefore, in variable driver, only store the original value for other use.\r
+    //\r
+    AsciiStrnCpy (mVariableModuleGlobal->LangCodes, Data, DataSize);\r
+  } else if (StrCmp (VariableName, L"PlatformLang") == 0) {\r
+    ASSERT (AsciiStrLen (mVariableModuleGlobal->PlatformLangCodes) != 0);\r
+\r
+    //\r
+    // When setting PlatformLang, firstly get most matched language string from supported language codes.\r
+    //\r
+    BestPlatformLang = GetBestLanguage(mVariableModuleGlobal->PlatformLangCodes, FALSE, Data);\r
+\r
+    //\r
+    // Get the corresponding index in language codes.\r
+    //\r
+    Index = GetIndexFromSupportedLangCodes(mVariableModuleGlobal->PlatformLangCodes, BestPlatformLang, FALSE);\r
+\r
+    //\r
+    // Get the corresponding ISO639 language tag according to RFC3066 language tag.\r
+    //\r
+    BestLang = GetLangFromSupportedLangCodes(mVariableModuleGlobal->LangCodes, Index, TRUE);\r
+\r
+    //\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
+\r
+    Status = UpdateVariable(L"Lang", &gEfiGlobalVariableGuid, \r
+                    BestLang, ISO_639_2_ENTRY_SIZE + 1, Attributes, &Variable);\r
+\r
+    DEBUG((EFI_D_INFO, "Variable Driver Auto Update PlatformLang, PlatformLang:%a, Lang:%a\n", BestPlatformLang, BestLang));\r
+\r
+    ASSERT_EFI_ERROR(Status);\r
+\r
+  } else if (StrCmp (VariableName, L"Lang") == 0) {\r
+    ASSERT (AsciiStrLen (mVariableModuleGlobal->LangCodes) != 0);\r
+\r
+    //\r
+    // When setting Lang, firstly get most matched language string from supported language codes.\r
+    //\r
+    BestLang = GetBestLanguage(mVariableModuleGlobal->LangCodes, TRUE, Data);\r
+\r
+    //\r
+    // Get the corresponding index in language codes.\r
+    //\r
+    Index = GetIndexFromSupportedLangCodes(mVariableModuleGlobal->LangCodes, BestLang, TRUE);\r
+\r
+    //\r
+    // Get the corresponding RFC3066 language tag according to ISO639 language tag.\r
+    //\r
+    BestPlatformLang = GetLangFromSupportedLangCodes(mVariableModuleGlobal->PlatformLangCodes, Index, FALSE);\r
+\r
+    //\r
+    // Successfully convert Lang to PlatformLang, and set the BestPlatformLang value into PlatformLang variable simultaneously.\r
+    //\r
+    FindVariable(L"PlatformLang", &gEfiGlobalVariableGuid, &Variable, (VARIABLE_GLOBAL *)mVariableModuleGlobal);\r
+\r
+    Status = UpdateVariable(L"PlatformLang", &gEfiGlobalVariableGuid, \r
+                    BestPlatformLang, AsciiStrLen (BestPlatformLang), Attributes, &Variable);\r
+\r
+    DEBUG((EFI_D_INFO, "Variable Driver Auto Update Lang, Lang:%a, PlatformLang:%a\n", BestLang, BestPlatformLang));\r
+    ASSERT_EFI_ERROR(Status);\r
+  }\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Update the variable region with Variable information. These are the same \r
+  arguments as the EFI Variable services.\r
+\r
+  @param[in] VariableName       Name of variable\r
+\r
+  @param[in] VendorGuid         Guid of variable\r
+\r
+  @param[in] Data               Variable data\r
+\r
+  @param[in] DataSize           Size of data. 0 means delete\r
+\r
+  @param[in] Attributes         Attribues of the variable\r
+\r
+  @param[in] Variable           The variable information which is used to keep track of variable usage.\r
+\r
+  @retval EFI_SUCCESS           The update operation is success.\r
+\r
+  @retval EFI_OUT_OF_RESOURCES  Variable region is full, can not write other data into this region.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+UpdateVariable (\r
+  IN      CHAR16          *VariableName,\r
+  IN      EFI_GUID        *VendorGuid,\r
+  IN      VOID            *Data,\r
+  IN      UINTN           DataSize,\r
+  IN      UINT32          Attributes OPTIONAL,\r
+  IN      VARIABLE_POINTER_TRACK *Variable\r
+  )\r
+{\r
+  EFI_STATUS              Status;\r
+  VARIABLE_HEADER         *NextVariable;\r
+  UINTN                   VarNameSize;\r
+  UINTN                   VarNameOffset;\r
+  UINTN                   VarDataOffset;\r
+  UINTN                   VarSize;\r
+  VARIABLE_GLOBAL         *Global;\r
+  UINTN                               NonVolatileVarableStoreSize;\r
+\r
+  Global = &mVariableModuleGlobal->VariableGlobal[Physical];\r
+\r
+  if (Variable->CurrPtr != NULL) {\r
+    //\r
+    // Update/Delete existing variable\r
+    //\r
+\r
+    if (EfiAtRuntime ()) {        \r
+      //\r
+      // If EfiAtRuntime and the variable is Volatile and Runtime Access,  \r
+      // the volatile is ReadOnly, and SetVariable should be aborted and \r
+      // return EFI_WRITE_PROTECTED.\r
+      //\r
+      if (Variable->Volatile) {\r
+        Status = EFI_WRITE_PROTECTED;\r
+        goto Done;\r
+      }\r
+      //\r
+      // Only variable have NV attribute can be updated/deleted in Runtime\r
+      //\r
+      if ((Variable->CurrPtr->Attributes & EFI_VARIABLE_NON_VOLATILE) == 0) {\r
+        Status = EFI_INVALID_PARAMETER;\r
+        goto Done;\r
+      }\r
+    }\r
+\r
+    //\r
+    // Setting a data variable with no access, or zero DataSize attributes\r
+    // specified causes it to be deleted.\r
+    //\r
+    if (DataSize == 0 || (Attributes & (EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS)) == 0) {\r
+      Variable->CurrPtr->State &= VAR_DELETED;\r
+      UpdateVariableInfo (VariableName, VendorGuid, Variable->Volatile, FALSE, FALSE, TRUE, FALSE);\r
+      Status = EFI_SUCCESS;\r
+      goto Done;\r
+    }\r
+\r
+    //\r
+    // If the variable is marked valid and the same data has been passed in\r
+    // then return to the caller immediately.\r
+    //\r
+    if (Variable->CurrPtr->DataSize == DataSize &&\r
+        CompareMem (Data, GetVariableDataPtr (Variable->CurrPtr), DataSize) == 0\r
+          ) {\r
+      Status = EFI_SUCCESS;\r
+      goto Done;\r
+    } else if (Variable->CurrPtr->State == VAR_ADDED) {\r
+      //\r
+      // Mark the old variable as in delete transition\r
+      //\r
+      Variable->CurrPtr->State &= VAR_IN_DELETED_TRANSITION;\r
+    }\r
+    \r
+  } else {\r
+    //\r
+    // No found existing variable, Create a new variable\r
+    //  \r
+    \r
+    //\r
+    // Make sure we are trying to create a new variable.\r
+    // Setting a data variable with no access, or zero DataSize attributes means to delete it.    \r
+    //\r
+    if (DataSize == 0 || (Attributes & (EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS)) == 0) {\r
+      Status = EFI_NOT_FOUND;\r
+      goto Done;\r
+    }\r
+        \r
+    //\r
+    // Only variable have NV|RT attribute can be created in Runtime\r
+    //\r
+    if (EfiAtRuntime () &&\r
+        (((Attributes & EFI_VARIABLE_RUNTIME_ACCESS) == 0) || ((Attributes & EFI_VARIABLE_NON_VOLATILE) == 0))) {\r
+      Status = EFI_INVALID_PARAMETER;\r
+      goto Done;\r
+    }         \r
+  }\r
+  \r
+  //\r
+  // Function part - create a new variable and copy the data.\r
+  // Both update a variable and create a variable will come here.\r
+  //\r
+  \r
+  VarNameOffset = sizeof (VARIABLE_HEADER);\r
+  VarNameSize   = StrSize (VariableName);\r
+  VarDataOffset = VarNameOffset + VarNameSize + GET_PAD_SIZE (VarNameSize);\r
+  VarSize       = VarDataOffset + DataSize + GET_PAD_SIZE (DataSize);\r
+\r
+  if ((Attributes & EFI_VARIABLE_NON_VOLATILE) != 0) {\r
+    NonVolatileVarableStoreSize = ((VARIABLE_STORE_HEADER *)(UINTN)(Global->NonVolatileVariableBase))->Size;\r
+    if ((((Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) != 0) \r
+      && ((VarSize + mVariableModuleGlobal->HwErrVariableTotalSize) > FixedPcdGet32(PcdHwErrStorageSize)))\r
+      || (((Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == 0) \r
+      && ((VarSize + mVariableModuleGlobal->CommonVariableTotalSize) > NonVolatileVarableStoreSize - sizeof (VARIABLE_STORE_HEADER) - FixedPcdGet32(PcdHwErrStorageSize)))) {\r
+      Status = EFI_OUT_OF_RESOURCES;\r
+      goto Done;\r
+    }\r
+\r
+    NextVariable  = (VARIABLE_HEADER *) (UINT8 *) (mVariableModuleGlobal->NonVolatileLastVariableOffset\r
+                      + (UINTN) Global->NonVolatileVariableBase);\r
+    mVariableModuleGlobal->NonVolatileLastVariableOffset += VarSize;\r
+\r
+    if ((Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) != 0) {\r
+      mVariableModuleGlobal->HwErrVariableTotalSize += VarSize;\r
+    } else {\r
+      mVariableModuleGlobal->CommonVariableTotalSize += VarSize;\r
+    }\r
+  } else {\r
+    if ((UINT32) (VarSize + mVariableModuleGlobal->VolatileLastVariableOffset) >\r
+          ((VARIABLE_STORE_HEADER *) ((UINTN) (Global->VolatileVariableBase)))->Size\r
+          ) {\r
+      Status = EFI_OUT_OF_RESOURCES;\r
+      goto Done;\r
+    }\r
+\r
+    NextVariable    = (VARIABLE_HEADER *) (UINT8 *) (mVariableModuleGlobal->VolatileLastVariableOffset\r
+                        + (UINTN) Global->VolatileVariableBase);\r
+    mVariableModuleGlobal->VolatileLastVariableOffset += VarSize;\r
+  }\r
+\r
+  NextVariable->StartId     = VARIABLE_DATA;\r
+  NextVariable->Attributes  = Attributes;\r
+  NextVariable->State       = VAR_ADDED;\r
+  NextVariable->Reserved    = 0;\r
+\r
+  //\r
+  // There will be pad bytes after Data, the NextVariable->NameSize and\r
+  // NextVariable->NameSize should not include pad size so that variable\r
+  // service can get actual size in GetVariable\r
   //\r
-  VarHeader = (VARIABLE_HEADER *) (GetVariableDataPtr (Variable) + Variable->DataSize + GET_PAD_SIZE (Variable->DataSize));\r
-\r
-  if (VarHeader->StartId != VARIABLE_DATA ||\r
-      (sizeof (VARIABLE_HEADER) + VarHeader->DataSize + VarHeader->NameSize) > MAX_VARIABLE_SIZE\r
-      ) {\r
-    return NULL;\r
-  }\r
+  NextVariable->NameSize  = (UINT32)VarNameSize;\r
+  NextVariable->DataSize  = (UINT32)DataSize;\r
 \r
-  return VarHeader;\r
-}\r
+  CopyMem (&NextVariable->VendorGuid, VendorGuid, sizeof (EFI_GUID));\r
+  CopyMem (\r
+    (UINT8 *) ((UINTN) NextVariable + VarNameOffset),\r
+    VariableName,\r
+    VarNameSize\r
+    );\r
+  CopyMem (\r
+    (UINT8 *) ((UINTN) NextVariable + VarDataOffset),\r
+    Data,\r
+    DataSize\r
+    );\r
 \r
-STATIC\r
-VARIABLE_HEADER *\r
-GetEndPointer (\r
-  IN VARIABLE_STORE_HEADER       *VolHeader\r
-  )\r
-/*++\r
+  //\r
+  // Mark the old variable as deleted\r
+  //\r
+  Variable->CurrPtr->State &= VAR_DELETED;\r
 \r
-Routine Description:\r
+  UpdateVariableInfo (VariableName, VendorGuid, Variable->Volatile, FALSE, TRUE, FALSE, FALSE);\r
 \r
-  This code gets the pointer to the last variable memory pointer byte\r
+  Status = EFI_SUCCESS;\r
 \r
-Arguments:\r
+Done:\r
+  return Status;\r
+}\r
 \r
-  Variable                  Pointer to the Variable Header.\r
+/**\r
+  Finds variable in storage blocks of volatile and non-volatile storage areas.\r
 \r
-Returns:\r
+  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
 \r
-  VARIABLE_HEADER*      Pointer to last unavailable Variable Header\r
+  @param  VariableName                Name of the variable to be found.\r
+  @param  VendorGuid                  Vendor GUID to be found.\r
+  @param  PtrTrack                    VARIABLE_POINTER_TRACK structure for output,\r
+                                      including the range searched and the target position.\r
+  @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
 \r
---*/\r
-{\r
-  //\r
-  // The end of variable store\r
-  //\r
-  return (VARIABLE_HEADER *) ((UINTN) VolHeader + VolHeader->Size);\r
-}\r
+  @retval EFI_INVALID_PARAMETER       If VariableName is not an empty string, while\r
+                                      VendorGuid is NULL.\r
+  @retval EFI_SUCCESS                 Variable successfully found.\r
+  @retval EFI_NOT_FOUND               Variable not found.\r
 \r
-STATIC\r
+**/\r
 EFI_STATUS\r
 FindVariable (\r
   IN  CHAR16                  *VariableName,\r
@@ -158,26 +806,6 @@ FindVariable (
   OUT VARIABLE_POINTER_TRACK  *PtrTrack,\r
   IN  VARIABLE_GLOBAL         *Global\r
   )\r
-/*++\r
-\r
-Routine Description:\r
-\r
-  This code finds variable in storage blocks (Volatile or Non-Volatile)\r
-\r
-Arguments:\r
-\r
-  VariableName                Name of the variable to be found\r
-  VendorGuid                  Vendor GUID to be found.\r
-  PtrTrack                    Variable Track Pointer structure that contains\r
-                              Variable Information.\r
-                              Contains the pointer of Variable header.\r
-  Global                      VARIABLE_GLOBAL pointer\r
-\r
-Returns:\r
-\r
-  EFI STATUS\r
-\r
---*/\r
 {\r
   VARIABLE_HEADER       *Variable[2];\r
   VARIABLE_STORE_HEADER *VariableStoreHeader[2];\r
@@ -213,16 +841,16 @@ Returns:
     PtrTrack->StartPtr  = (VARIABLE_HEADER *) (VariableStoreHeader[Index] + 1);\r
     PtrTrack->EndPtr    = GetEndPointer (VariableStoreHeader[Index]);\r
 \r
-    while ((Variable[Index] != NULL) && (Variable[Index] <= GetEndPointer (VariableStoreHeader[Index]))) {\r
+    while ((Variable[Index] < GetEndPointer (VariableStoreHeader[Index])) && (Variable[Index] != NULL)) {\r
       if (Variable[Index]->StartId == VARIABLE_DATA && Variable[Index]->State == VAR_ADDED) {\r
-        if (!(EfiAtRuntime () && !(Variable[Index]->Attributes & EFI_VARIABLE_RUNTIME_ACCESS))) {\r
+        if (!(EfiAtRuntime () && ((Variable[Index]->Attributes & EFI_VARIABLE_RUNTIME_ACCESS) == 0))) {\r
           if (VariableName[0] == 0) {\r
             PtrTrack->CurrPtr   = Variable[Index];\r
             PtrTrack->Volatile  = (BOOLEAN) Index;\r
             return EFI_SUCCESS;\r
           } else {\r
             if (CompareGuid (VendorGuid, &Variable[Index]->VendorGuid)) {\r
-              if (!CompareMem (VariableName, GET_VARIABLE_NAME_PTR (Variable[Index]), Variable[Index]->NameSize)) {\r
+              if (CompareMem (VariableName, GET_VARIABLE_NAME_PTR (Variable[Index]), Variable[Index]->NameSize) == 0) {\r
                 PtrTrack->CurrPtr   = Variable[Index];\r
                 PtrTrack->Volatile  = (BOOLEAN) Index;\r
                 return EFI_SUCCESS;\r
@@ -239,43 +867,37 @@ Returns:
   return EFI_NOT_FOUND;\r
 }\r
 \r
+/**\r
+  This code finds variable in storage blocks (Volatile or Non-Volatile).\r
+  \r
+  @param  VariableName           A Null-terminated Unicode string that is the name of\r
+                                 the vendor's variable.\r
+  @param  VendorGuid             A unique identifier for the vendor.\r
+  @param  Attributes             If not NULL, a pointer to the memory location to return the \r
+                                 attributes bitmask for the variable.\r
+  @param  DataSize               Size of Data found. If size is less than the\r
+                                 data, this value contains the required size.\r
+  @param  Data                   On input, the size in bytes of the return Data buffer.  \r
+                                 On output, the size of data returned in Data.\r
+  @param  Global                 Pointer to VARIABLE_GLOBAL structure\r
+\r
+  @retval EFI_SUCCESS            The function completed successfully. \r
+  @retval EFI_NOT_FOUND          The variable was not found.\r
+  @retval EFI_BUFFER_TOO_SMALL   DataSize is too small for the result.  DataSize has \r
+                                 been updated with the size needed to complete the request.\r
+  @retval EFI_INVALID_PARAMETER  VariableName or VendorGuid or DataSize is NULL.\r
+\r
+**/\r
 EFI_STATUS\r
 EFIAPI\r
-GetVariable (\r
+EmuGetVariable (\r
   IN      CHAR16            *VariableName,\r
-  IN      EFI_GUID          * VendorGuid,\r
+  IN      EFI_GUID          *VendorGuid,\r
   OUT     UINT32            *Attributes OPTIONAL,\r
   IN OUT  UINTN             *DataSize,\r
   OUT     VOID              *Data,\r
-  IN      VARIABLE_GLOBAL   * Global,\r
-  IN      UINT32            Instance\r
+  IN      VARIABLE_GLOBAL   *Global\r
   )\r
-/*++\r
-\r
-Routine Description:\r
-\r
-  This code finds variable in storage blocks (Volatile or Non-Volatile)\r
-\r
-Arguments:\r
-\r
-  VariableName                    Name of Variable to be found\r
-  VendorGuid                      Variable vendor GUID\r
-  Attributes OPTIONAL             Attribute value of the variable found\r
-  DataSize                        Size of Data found. If size is less than the\r
-                                  data, this value contains the required size.\r
-  Data                            Data pointer\r
-  Global                          Pointer to VARIABLE_GLOBAL structure\r
-  Instance                        Instance of the Firmware Volume.\r
-\r
-Returns:\r
-\r
-  EFI_INVALID_PARAMETER       - Invalid parameter\r
-  EFI_SUCCESS                 - Find the specified variable\r
-  EFI_NOT_FOUND               - Not found\r
-  EFI_BUFFER_TO_SMALL         - DataSize is too small for the result\r
-\r
-\r
---*/\r
 {\r
   VARIABLE_POINTER_TRACK  Variable;\r
   UINTN                   VarDataSize;\r
@@ -308,6 +930,7 @@ Returns:
     }\r
 \r
     *DataSize = VarDataSize;\r
+    UpdateVariableInfo (VariableName, VendorGuid, Variable.Volatile, TRUE, FALSE, FALSE, FALSE);\r
     Status = EFI_SUCCESS;\r
     goto Done;\r
   } else {\r
@@ -321,34 +944,32 @@ Done:
   return Status;\r
 }\r
 \r
+/**\r
+\r
+  This code Finds the Next available variable.\r
+\r
+  @param  VariableNameSize       Size of the variable.\r
+  @param  VariableName           On input, supplies the last VariableName that was returned by GetNextVariableName().\r
+                                 On output, returns the Null-terminated Unicode string of the current variable.\r
+  @param  VendorGuid             On input, supplies the last VendorGuid that was returned by GetNextVariableName().\r
+                                 On output, returns the VendorGuid of the current variable.  \r
+  @param  Global                 Pointer to VARIABLE_GLOBAL structure.\r
+\r
+  @retval EFI_SUCCESS            The function completed successfully. \r
+  @retval EFI_NOT_FOUND          The next variable was not found.\r
+  @retval EFI_BUFFER_TOO_SMALL   VariableNameSize is too small for the result. \r
+                                 VariableNameSize has been updated with the size needed to complete the request.\r
+  @retval EFI_INVALID_PARAMETER  VariableNameSize or VariableName or VendorGuid is NULL.\r
+\r
+**/\r
 EFI_STATUS\r
 EFIAPI\r
-GetNextVariableName (\r
+EmuGetNextVariableName (\r
   IN OUT  UINTN             *VariableNameSize,\r
   IN OUT  CHAR16            *VariableName,\r
   IN OUT  EFI_GUID          *VendorGuid,\r
-  IN      VARIABLE_GLOBAL   *Global,\r
-  IN      UINT32            Instance\r
+  IN      VARIABLE_GLOBAL   *Global\r
   )\r
-/*++\r
-\r
-Routine Description:\r
-\r
-  This code Finds the Next available variable\r
-\r
-Arguments:\r
-\r
-  VariableNameSize            Size of the variable\r
-  VariableName                Pointer to variable name\r
-  VendorGuid                  Variable Vendor Guid\r
-  Global                      VARIABLE_GLOBAL structure pointer.\r
-  Instance                    FV instance\r
-\r
-Returns:\r
-\r
-  EFI STATUS\r
-\r
---*/\r
 {\r
   VARIABLE_POINTER_TRACK  Variable;\r
   UINTN                   VarNameSize;\r
@@ -394,7 +1015,7 @@ Returns:
     // Variable is found\r
     //\r
     if (Variable.CurrPtr->StartId == VARIABLE_DATA && Variable.CurrPtr->State == VAR_ADDED) {\r
-      if (!(EfiAtRuntime () && !(Variable.CurrPtr->Attributes & EFI_VARIABLE_RUNTIME_ACCESS))) {\r
+      if (!(EfiAtRuntime () && ((Variable.CurrPtr->Attributes & EFI_VARIABLE_RUNTIME_ACCESS) == 0))) {\r
         VarNameSize = Variable.CurrPtr->NameSize;\r
         if (VarNameSize <= *VariableNameSize) {\r
           CopyMem (\r
@@ -424,9 +1045,38 @@ Done:
 \r
 }\r
 \r
+/**\r
+\r
+  This code sets variable in storage blocks (Volatile or Non-Volatile).\r
+\r
+  @param  VariableName           A Null-terminated Unicode string that is the name of the vendor's\r
+                                 variable.  Each VariableName is unique for each \r
+                                 VendorGuid.  VariableName must contain 1 or more \r
+                                 Unicode characters.  If VariableName is an empty Unicode \r
+                                 string, then EFI_INVALID_PARAMETER is returned.\r
+  @param  VendorGuid             A unique identifier for the vendor\r
+  @param  Attributes             Attributes bitmask to set for the variable\r
+  @param  DataSize               The size in bytes of the Data buffer.  A size of zero causes the\r
+                                 variable to be deleted.\r
+  @param  Data                   The contents for the variable\r
+  @param  Global                 Pointer to VARIABLE_GLOBAL structure\r
+  @param  VolatileOffset         The offset of last volatile variable\r
+  @param  NonVolatileOffset      The offset of last non-volatile variable\r
+\r
+  @retval EFI_SUCCESS            The firmware has successfully stored the variable and its data as \r
+                                 defined by the Attributes.\r
+  @retval EFI_INVALID_PARAMETER  An invalid combination of attribute bits was supplied, or the \r
+                                 DataSize exceeds the maximum allowed, or VariableName is an empty \r
+                                 Unicode string, or VendorGuid is NULL.\r
+  @retval EFI_OUT_OF_RESOURCES   Not enough storage is available to hold the variable and its data.\r
+  @retval EFI_DEVICE_ERROR       The variable could not be saved due to a hardware failure.\r
+  @retval EFI_WRITE_PROTECTED    The variable in question is read-only or cannot be deleted.\r
+  @retval EFI_NOT_FOUND          The variable trying to be updated or deleted was not found.\r
+\r
+**/\r
 EFI_STATUS\r
 EFIAPI\r
-SetVariable (\r
+EmuSetVariable (\r
   IN CHAR16                  *VariableName,\r
   IN EFI_GUID                *VendorGuid,\r
   IN UINT32                  Attributes,\r
@@ -434,46 +1084,11 @@ SetVariable (
   IN VOID                    *Data,\r
   IN VARIABLE_GLOBAL         *Global,\r
   IN UINTN                   *VolatileOffset,\r
-  IN UINTN                   *NonVolatileOffset,\r
-  IN UINT32                  Instance\r
+  IN UINTN                   *NonVolatileOffset\r
   )\r
-/*++\r
-\r
-Routine Description:\r
-\r
-  This code sets variable in storage blocks (Volatile or Non-Volatile)\r
-\r
-Arguments:\r
-\r
-  VariableName                    Name of Variable to be found\r
-  VendorGuid                      Variable vendor GUID\r
-  Attributes                      Attribute value of the variable found\r
-  DataSize                        Size of Data found. If size is less than the\r
-                                  data, this value contains the required size.\r
-  Data                            Data pointer\r
-  Global                          Pointer to VARIABLE_GLOBAL structure\r
-  VolatileOffset                  The offset of last volatile variable\r
-  NonVolatileOffset               The offset of last non-volatile variable\r
-  Instance                        Instance of the Firmware Volume.\r
-\r
-Returns:\r
-\r
-  EFI_INVALID_PARAMETER           - Invalid parameter\r
-  EFI_SUCCESS                     - Set successfully\r
-  EFI_OUT_OF_RESOURCES            - Resource not enough to set variable\r
-  EFI_NOT_FOUND                   - Not found\r
-  EFI_DEVICE_ERROR                - Variable can not be saved due to hardware failure\r
-  EFI_WRITE_PROTECTED             - Variable is read-only\r
-\r
---*/\r
 {\r
   VARIABLE_POINTER_TRACK  Variable;\r
   EFI_STATUS              Status;\r
-  VARIABLE_HEADER         *NextVariable;\r
-  UINTN                   VarNameSize;\r
-  UINTN                   VarNameOffset;\r
-  UINTN                   VarDataOffset;\r
-  UINTN                   VarSize;\r
 \r
   //\r
   // Check input parameters\r
@@ -489,222 +1104,88 @@ Returns:
   }\r
   //\r
   //  The size of the VariableName, including the Unicode Null in bytes plus\r
-  //  the DataSize is limited to maximum size of MAX_HARDWARE_ERROR_VARIABLE_SIZE (32K)\r
-  //  bytes for HwErrRec, and MAX_VARIABLE_SIZE (1024) bytes for the others.\r
+  //  the DataSize is limited to maximum size of FixedPcdGet32(PcdMaxHardwareErrorVariableSize)\r
+  //  bytes for HwErrRec, and FixedPcdGet32(PcdMaxVariableSize) bytes for the others.\r
   //\r
   if ((Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == EFI_VARIABLE_HARDWARE_ERROR_RECORD) {\r
-    if ((DataSize > MAX_HARDWARE_ERROR_VARIABLE_SIZE) ||                                                       \r
-        (sizeof (VARIABLE_HEADER) + StrSize (VariableName) + DataSize > MAX_HARDWARE_ERROR_VARIABLE_SIZE)) {\r
+    if ((DataSize > FixedPcdGet32(PcdMaxHardwareErrorVariableSize)) ||                                                       \r
+        (sizeof (VARIABLE_HEADER) + StrSize (VariableName) + DataSize > FixedPcdGet32(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
       return EFI_INVALID_PARAMETER;\r
-    }    \r
+    }\r
   } else {\r
   //\r
   //  The size of the VariableName, including the Unicode Null in bytes plus\r
-  //  the DataSize is limited to maximum size of MAX_VARIABLE_SIZE (1024) bytes.\r
+  //  the DataSize is limited to maximum size of FixedPcdGet32(PcdMaxVariableSize) bytes.\r
   //\r
-    if ((DataSize > MAX_VARIABLE_SIZE) ||\r
-        (sizeof (VARIABLE_HEADER) + StrSize (VariableName) + DataSize > MAX_VARIABLE_SIZE)) {\r
+    if ((DataSize > FixedPcdGet32(PcdMaxVariableSize)) ||\r
+        (sizeof (VARIABLE_HEADER) + StrSize (VariableName) + DataSize > FixedPcdGet32(PcdMaxVariableSize))) {\r
       return EFI_INVALID_PARAMETER;\r
     }  \r
-  }  \r
+  }\r
+\r
   //\r
   // Check whether the input variable is already existed\r
   //\r
   \r
   Status = FindVariable (VariableName, VendorGuid, &Variable, Global);\r
 \r
-  if (Status == EFI_SUCCESS && Variable.CurrPtr != NULL) {\r
-    //\r
-    // Update/Delete existing variable\r
-    //\r
-\r
-    if (EfiAtRuntime ()) {        \r
-      //\r
-      // If EfiAtRuntime and the variable is Volatile and Runtime Access,  \r
-      // the volatile is ReadOnly, and SetVariable should be aborted and \r
-      // return EFI_WRITE_PROTECTED.\r
-      //\r
-      if (Variable.Volatile) {\r
-        Status = EFI_WRITE_PROTECTED;\r
-        goto Done;\r
-      }\r
-      //\r
-      // Only variable have NV attribute can be updated/deleted in Runtime\r
-      //\r
-      if (!(Variable.CurrPtr->Attributes & EFI_VARIABLE_NON_VOLATILE)) {\r
-        Status = EFI_INVALID_PARAMETER;\r
-        goto Done;\r
-      }\r
-    }\r
-\r
-    //\r
-    // Setting a data variable with no access, or zero DataSize attributes\r
-    // specified causes it to be deleted.\r
-    //\r
-    if (DataSize == 0 || (Attributes & (EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS)) == 0) {\r
-      Variable.CurrPtr->State &= VAR_DELETED;\r
-      Status = EFI_SUCCESS;\r
-      goto Done;\r
-    }\r
-\r
-    //\r
-    // If the variable is marked valid and the same data has been passed in\r
-    // then return to the caller immediately.\r
-    //\r
-    if (Variable.CurrPtr->DataSize == DataSize &&\r
-        !CompareMem (Data, GetVariableDataPtr (Variable.CurrPtr), DataSize)\r
-          ) {\r
-      Status = EFI_SUCCESS;\r
-      goto Done;\r
-    } else if (Variable.CurrPtr->State == VAR_ADDED) {\r
-      //\r
-      // Mark the old variable as in delete transition\r
-      //\r
-      Variable.CurrPtr->State &= VAR_IN_DELETED_TRANSITION;\r
-    }\r
-    \r
-  } else if (Status == EFI_NOT_FOUND) {\r
-    //\r
-    // Create a new variable\r
-    //  \r
-    \r
-    //\r
-    // Make sure we are trying to create a new variable.\r
-    // Setting a data variable with no access, or zero DataSize attributes means to delete it.    \r
-    //\r
-    if (DataSize == 0 || (Attributes & (EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS)) == 0) {\r
-      Status = EFI_NOT_FOUND;\r
-      goto Done;\r
-    }\r
-        \r
-    //\r
-    // Only variable have NV|RT attribute can be created in Runtime\r
-    //\r
-    if (EfiAtRuntime () &&\r
-        (!(Attributes & EFI_VARIABLE_RUNTIME_ACCESS) || !(Attributes & EFI_VARIABLE_NON_VOLATILE))) {\r
-      Status = EFI_INVALID_PARAMETER;\r
-      goto Done;\r
-    }         \r
-  } else {\r
-    //\r
-    // Status should be EFI_INVALID_PARAMETER here according to return status of FindVariable().\r
-    //\r
-    ASSERT (Status == EFI_INVALID_PARAMETER);\r
-    goto Done;\r
-  } \r
-  \r
-  //\r
-  // Function part - create a new variable and copy the data.\r
-  // Both update a variable and create a variable will come here.\r
-  //\r
-  \r
-  VarNameOffset = sizeof (VARIABLE_HEADER);\r
-  VarNameSize   = StrSize (VariableName);\r
-  VarDataOffset = VarNameOffset + VarNameSize + GET_PAD_SIZE (VarNameSize);\r
-  VarSize       = VarDataOffset + DataSize + GET_PAD_SIZE (DataSize);\r
-\r
-  if (Attributes & EFI_VARIABLE_NON_VOLATILE) {\r
-    if ((UINT32) (VarSize +*NonVolatileOffset) >\r
-          ((VARIABLE_STORE_HEADER *) ((UINTN) (Global->NonVolatileVariableBase)))->Size\r
-          ) {\r
-      Status = EFI_OUT_OF_RESOURCES;\r
-      goto Done;\r
-    }\r
-\r
-    NextVariable        = (VARIABLE_HEADER *) (UINT8 *) (*NonVolatileOffset + (UINTN) Global->NonVolatileVariableBase);\r
-    *NonVolatileOffset  = *NonVolatileOffset + VarSize;\r
-  } else {\r
-    if ((UINT32) (VarSize +*VolatileOffset) >\r
-          ((VARIABLE_STORE_HEADER *) ((UINTN) (Global->VolatileVariableBase)))->Size\r
-          ) {\r
-      Status = EFI_OUT_OF_RESOURCES;\r
-      goto Done;\r
-    }\r
-\r
-    NextVariable    = (VARIABLE_HEADER *) (UINT8 *) (*VolatileOffset + (UINTN) Global->VolatileVariableBase);\r
-    *VolatileOffset = *VolatileOffset + VarSize;\r
-  }\r
-\r
-  NextVariable->StartId     = VARIABLE_DATA;\r
-  NextVariable->Attributes  = Attributes;\r
-  NextVariable->State       = VAR_ADDED;\r
-  NextVariable->Reserved    = 0;\r
-\r
   //\r
-  // There will be pad bytes after Data, the NextVariable->NameSize and\r
-  // NextVariable->NameSize should not include pad size so that variable\r
-  // service can get actual size in GetVariable\r
+  // Hook the operation of setting PlatformLangCodes/PlatformLang and LangCodes/Lang\r
   //\r
-  NextVariable->NameSize  = (UINT32)VarNameSize;\r
-  NextVariable->DataSize  = (UINT32)DataSize;\r
+  AutoUpdateLangVariable (VariableName, Data, DataSize);\r
 \r
-  CopyMem (&NextVariable->VendorGuid, VendorGuid, sizeof (EFI_GUID));\r
-  CopyMem (\r
-    (UINT8 *) ((UINTN) NextVariable + VarNameOffset),\r
-    VariableName,\r
-    VarNameSize\r
-    );\r
-  CopyMem (\r
-    (UINT8 *) ((UINTN) NextVariable + VarDataOffset),\r
-    Data,\r
-    DataSize\r
-    );\r
+  Status = UpdateVariable (VariableName, VendorGuid, Data, DataSize, Attributes, &Variable);\r
 \r
-  //\r
-  // Mark the old variable as deleted\r
-  //\r
-  if (!EFI_ERROR (Status)) {\r
-    Variable.CurrPtr->State &= VAR_DELETED;\r
-  }\r
-  \r
-  Status = EFI_SUCCESS;\r
-Done:\r
   ReleaseLockOnlyAtBootTime (&Global->VariableServicesLock);\r
   return Status;\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   On output the maximum size of the storage space available for \r
+                                       the EFI variables associated with the attributes specified.  \r
+  @param  RemainingVariableStorageSize Returns the remaining size of the storage space available for EFI \r
+                                       variables associated with the attributes specified.\r
+  @param  MaximumVariableSize          Returns the maximum size of an individual EFI variable \r
+                                       associated with the attributes specified.\r
+  @param  Global                       Pointer to VARIABLE_GLOBAL structure.\r
+\r
+  @retval EFI_SUCCESS                  Valid answer returned.\r
+  @retval EFI_INVALID_PARAMETER        An invalid combination of attribute bits was supplied\r
+  @retval EFI_UNSUPPORTED              The attribute is not supported on this platform, and the \r
+                                       MaximumVariableStorageSize, RemainingVariableStorageSize, \r
+                                       MaximumVariableSize are undefined.\r
+\r
+**/\r
 EFI_STATUS\r
 EFIAPI\r
-QueryVariableInfo (\r
+EmuQueryVariableInfo (\r
   IN  UINT32                 Attributes,\r
   OUT UINT64                 *MaximumVariableStorageSize,\r
   OUT UINT64                 *RemainingVariableStorageSize,\r
   OUT UINT64                 *MaximumVariableSize,\r
-  IN  VARIABLE_GLOBAL        *Global,\r
-  IN  UINT32                 Instance\r
+  IN  VARIABLE_GLOBAL        *Global\r
   )\r
-/*++\r
-\r
-Routine Description:\r
-\r
-  This code returns information about the EFI variables.\r
-\r
-Arguments:\r
-\r
-  Attributes                      Attributes bitmask to specify the type of variables\r
-                                  on which to return information.\r
-  MaximumVariableStorageSize      Pointer to the maximum size of the storage space available\r
-                                  for the EFI variables associated with the attributes specified.\r
-  RemainingVariableStorageSize    Pointer to the remaining size of the storage space available\r
-                                  for EFI variables associated with the attributes specified.\r
-  MaximumVariableSize             Pointer to the maximum size of an individual EFI variables\r
-                                  associated with the attributes specified.\r
-  Global                          Pointer to VARIABLE_GLOBAL structure.\r
-  Instance                        Instance of the Firmware Volume.\r
-\r
-Returns:\r
-\r
-  EFI STATUS\r
-  EFI_INVALID_PARAMETER           - An invalid combination of attribute bits was supplied.\r
-  EFI_SUCCESS                     - Query successfully.\r
-  EFI_UNSUPPORTED                 - The attribute is not supported on this platform.\r
-\r
---*/\r
 {\r
   VARIABLE_HEADER        *Variable;\r
   VARIABLE_HEADER        *NextVariable;\r
   UINT64                 VariableSize;\r
   VARIABLE_STORE_HEADER  *VariableStoreHeader;\r
+  UINT64                 CommonVariableTotalSize;\r
+  UINT64                 HwErrVariableTotalSize;\r
+\r
+  CommonVariableTotalSize = 0;\r
+  HwErrVariableTotalSize = 0;\r
 \r
   if(MaximumVariableStorageSize == NULL || RemainingVariableStorageSize == NULL || MaximumVariableSize == NULL || Attributes == 0) {\r
     return EFI_INVALID_PARAMETER;\r
@@ -720,11 +1201,16 @@ Returns:
     // Make sure if runtime bit is set, boot service bit is set also.\r
     //\r
     return EFI_INVALID_PARAMETER;\r
-  } else if (EfiAtRuntime () && !(Attributes & EFI_VARIABLE_RUNTIME_ACCESS)) {\r
+  } else if (EfiAtRuntime () && ((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
   }\r
 \r
   AcquireLockOnlyAtBootTime(&Global->VariableServicesLock);\r
@@ -746,18 +1232,23 @@ Returns:
   // with the storage size (excluding the storage header size)\r
   //\r
   *MaximumVariableStorageSize   = VariableStoreHeader->Size - sizeof (VARIABLE_STORE_HEADER);\r
-  *RemainingVariableStorageSize = VariableStoreHeader->Size - sizeof (VARIABLE_STORE_HEADER);\r
-\r
-  //\r
-  // Let *MaximumVariableSize be MAX_VARIABLE_SIZE with the exception of the variable header size.\r
-  //\r
-  *MaximumVariableSize = MAX_VARIABLE_SIZE - sizeof (VARIABLE_HEADER);\r
 \r
   //\r
   // Harware error record variable needs larger size.\r
   //\r
-  if ((Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == EFI_VARIABLE_HARDWARE_ERROR_RECORD) {\r
-    *MaximumVariableSize = MAX_HARDWARE_ERROR_VARIABLE_SIZE - sizeof (VARIABLE_HEADER);\r
+  if ((Attributes & (EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_HARDWARE_ERROR_RECORD)) == (EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_HARDWARE_ERROR_RECORD)) {\r
+    *MaximumVariableStorageSize = FixedPcdGet32(PcdHwErrStorageSize);\r
+    *MaximumVariableSize = FixedPcdGet32(PcdMaxHardwareErrorVariableSize) - sizeof (VARIABLE_HEADER);\r
+  } else {\r
+    if ((Attributes & EFI_VARIABLE_NON_VOLATILE) != 0) {\r
+      ASSERT (FixedPcdGet32(PcdHwErrStorageSize) < VariableStoreHeader->Size);\r
+      *MaximumVariableStorageSize = VariableStoreHeader->Size - sizeof (VARIABLE_STORE_HEADER) - FixedPcdGet32(PcdHwErrStorageSize);\r
+    }\r
+\r
+    //\r
+    // Let *MaximumVariableSize be FixedPcdGet32(PcdMaxVariableSize) with the exception of the variable header size.\r
+    //\r
+    *MaximumVariableSize = FixedPcdGet32(PcdMaxVariableSize) - sizeof (VARIABLE_HEADER);\r
   }\r
 \r
   //\r
@@ -769,15 +1260,16 @@ Returns:
   // Now walk through the related variable store.\r
   //\r
   while (Variable < GetEndPointer (VariableStoreHeader)) {\r
-    if (Variable->StartId != VARIABLE_DATA) {\r
+    NextVariable = GetNextVariablePtr(Variable);\r
+    if (NextVariable == NULL) {\r
       break;\r
     }\r
-\r
-    NextVariable = (VARIABLE_HEADER *) (GetVariableDataPtr (Variable) + Variable->DataSize + GET_PAD_SIZE (Variable->DataSize));\r
     VariableSize = (UINT64) (UINTN) NextVariable - (UINT64) (UINTN) Variable;\r
 \r
-    if (Variable->State == VAR_ADDED) {\r
-      *RemainingVariableStorageSize -= VariableSize;\r
+    if ((NextVariable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == EFI_VARIABLE_HARDWARE_ERROR_RECORD) {\r
+      HwErrVariableTotalSize += VariableSize;\r
+    } else {\r
+      CommonVariableTotalSize += VariableSize;\r
     }\r
 \r
     //\r
@@ -786,6 +1278,12 @@ Returns:
     Variable = NextVariable;\r
   }\r
 \r
+  if ((Attributes  & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == EFI_VARIABLE_HARDWARE_ERROR_RECORD){\r
+    *RemainingVariableStorageSize = *MaximumVariableStorageSize - HwErrVariableTotalSize;\r
+  } else {\r
+    *RemainingVariableStorageSize = *MaximumVariableStorageSize - CommonVariableTotalSize;\r
+  }\r
+\r
   if (*RemainingVariableStorageSize < sizeof (VARIABLE_HEADER)) {\r
     *MaximumVariableSize = 0;\r
   } else if ((*RemainingVariableStorageSize - sizeof (VARIABLE_HEADER)) < *MaximumVariableSize) {\r
@@ -796,22 +1294,20 @@ Returns:
   return EFI_SUCCESS;\r
 }\r
 \r
-STATIC\r
+/**\r
+  Initializes variable store area.\r
+\r
+  This function allocates memory space for variable store area and initializes its attributes.\r
+\r
+  @param  VariableBase         Base of the variable store area created\r
+  @param  LastVariableOffset   Size of VARIABLE_STORE_HEADER\r
+\r
+**/\r
 EFI_STATUS\r
 InitializeVariableStore (\r
   OUT EFI_PHYSICAL_ADDRESS  *VariableBase,\r
   OUT UINTN                 *LastVariableOffset\r
   )\r
-/*++\r
-\r
-Routine Description:\r
-  This function initializes variable store\r
-\r
-Arguments:\r
-\r
-Returns:\r
-\r
---*/\r
 {\r
   VARIABLE_STORE_HEADER *VariableStore;\r
 \r
@@ -819,13 +1315,13 @@ Returns:
   // Allocate memory for volatile variable store\r
   //\r
   VariableStore = (VARIABLE_STORE_HEADER *) AllocateRuntimePool (\r
-                                              VARIABLE_STORE_SIZE\r
+                                              FixedPcdGet32(PcdVariableStoreSize)\r
                                               );\r
   if (NULL == VariableStore) {\r
     return EFI_OUT_OF_RESOURCES;\r
   }\r
 \r
-  SetMem (VariableStore, VARIABLE_STORE_SIZE, 0xff);\r
+  SetMem (VariableStore, FixedPcdGet32(PcdVariableStoreSize), 0xff);\r
 \r
   //\r
   // Variable Specific Data\r
@@ -833,8 +1329,8 @@ Returns:
   *VariableBase             = (EFI_PHYSICAL_ADDRESS) (UINTN) VariableStore;\r
   *LastVariableOffset       = sizeof (VARIABLE_STORE_HEADER);\r
 \r
-  VariableStore->Signature  = VARIABLE_STORE_SIGNATURE;\r
-  VariableStore->Size       = VARIABLE_STORE_SIZE;\r
+  CopyGuid (&VariableStore->Signature, &gEfiVariableGuid);\r
+  VariableStore->Size       = FixedPcdGet32(PcdVariableStoreSize);\r
   VariableStore->Format     = VARIABLE_STORE_FORMATTED;\r
   VariableStore->State      = VARIABLE_STORE_HEALTHY;\r
   VariableStore->Reserved   = 0;\r
@@ -843,29 +1339,32 @@ Returns:
   return EFI_SUCCESS;\r
 }\r
 \r
+/**\r
+  Initializes variable store area for non-volatile and volatile variable.\r
+\r
+  This function allocates and initializes memory space for global context of ESAL\r
+  variable service and variable store area for non-volatile and volatile variable.\r
+\r
+  @param  ImageHandle           The Image handle of this driver.\r
+  @param  SystemTable           The pointer of EFI_SYSTEM_TABLE.\r
+\r
+  @retval EFI_SUCCESS           Function successfully executed.\r
+  @retval EFI_OUT_OF_RESOURCES  Fail to allocate enough memory resource.\r
+\r
+**/\r
 EFI_STATUS\r
 EFIAPI\r
 VariableCommonInitialize (\r
   IN EFI_HANDLE         ImageHandle,\r
   IN EFI_SYSTEM_TABLE   *SystemTable\r
   )\r
-/*++\r
-\r
-Routine Description:\r
-  This function does common initialization for variable services\r
-\r
-Arguments:\r
-\r
-Returns:\r
-\r
---*/\r
 {\r
   EFI_STATUS  Status;\r
 \r
   //\r
   // Allocate memory for mVariableModuleGlobal\r
   //\r
-  mVariableModuleGlobal = (ESAL_VARIABLE_GLOBAL *) AllocateRuntimePool (\r
+  mVariableModuleGlobal = (ESAL_VARIABLE_GLOBAL *) AllocateRuntimeZeroPool (\r
                                                     sizeof (ESAL_VARIABLE_GLOBAL)\r
                                                    );\r
   if (NULL == mVariableModuleGlobal) {\r
@@ -883,6 +1382,7 @@ Returns:
             );\r
 \r
   if (EFI_ERROR (Status)) {\r
+    FreePool(mVariableModuleGlobal);\r
     return Status;\r
   }\r
   //\r