+{\r
+ EFI_STATUS Status;\r
+ CHAR8 *BestPlatformLang;\r
+ CHAR8 *BestLang;\r
+ UINTN Index;\r
+ 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
+ //\r
+ if (DataSize == 0) {\r
+ return EFI_SUCCESS;\r
+ }\r
+\r
+ SetLanguageCodes = FALSE;\r
+\r
+ if (StrCmp (VariableName, EFI_PLATFORM_LANG_CODES_VARIABLE_NAME) == 0) {\r
+ //\r
+ // PlatformLangCodes is a volatile variable, so it can not be updated at runtime.\r
+ //\r
+ if (AtRuntime ()) {\r
+ return EFI_WRITE_PROTECTED;\r
+ }\r
+\r
+ SetLanguageCodes = TRUE;\r
+\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
+ if (mVariableModuleGlobal->PlatformLangCodes != NULL) {\r
+ FreePool (mVariableModuleGlobal->PlatformLangCodes);\r
+ }\r
+ mVariableModuleGlobal->PlatformLangCodes = AllocateRuntimeCopyPool (DataSize, Data);\r
+ ASSERT (mVariableModuleGlobal->PlatformLangCodes != NULL);\r
+\r
+ //\r
+ // PlatformLang holds a single language from PlatformLangCodes, \r
+ // so the size of PlatformLangCodes is enough for the PlatformLang.\r
+ //\r
+ if (mVariableModuleGlobal->PlatformLang != NULL) {\r
+ FreePool (mVariableModuleGlobal->PlatformLang);\r
+ }\r
+ mVariableModuleGlobal->PlatformLang = AllocateRuntimePool (DataSize);\r
+ ASSERT (mVariableModuleGlobal->PlatformLang != NULL);\r
+\r
+ } else if (StrCmp (VariableName, EFI_LANG_CODES_VARIABLE_NAME) == 0) {\r
+ //\r
+ // LangCodes is a volatile variable, so it can not be updated at runtime.\r
+ //\r
+ if (AtRuntime ()) {\r
+ return EFI_WRITE_PROTECTED;\r
+ }\r
+\r
+ SetLanguageCodes = TRUE;\r
+\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
+ if (mVariableModuleGlobal->LangCodes != NULL) {\r
+ FreePool (mVariableModuleGlobal->LangCodes);\r
+ }\r
+ mVariableModuleGlobal->LangCodes = AllocateRuntimeCopyPool (DataSize, Data);\r
+ ASSERT (mVariableModuleGlobal->LangCodes != NULL);\r
+ }\r
+\r
+ if (SetLanguageCodes \r
+ && (mVariableModuleGlobal->PlatformLangCodes != NULL)\r
+ && (mVariableModuleGlobal->LangCodes != NULL)) {\r
+ //\r
+ // Update Lang if PlatformLang is already set\r
+ // Update PlatformLang if Lang is already set\r
+ //\r
+ Status = FindVariable (EFI_PLATFORM_LANG_VARIABLE_NAME, &gEfiGlobalVariableGuid, &Variable, &mVariableModuleGlobal->VariableGlobal, FALSE);\r
+ if (!EFI_ERROR (Status)) {\r
+ //\r
+ // Update Lang\r
+ //\r
+ VariableName = EFI_PLATFORM_LANG_VARIABLE_NAME;\r
+ Data = GetVariableDataPtr (Variable.CurrPtr);\r
+ DataSize = Variable.CurrPtr->DataSize;\r
+ } else {\r
+ Status = FindVariable (EFI_LANG_VARIABLE_NAME, &gEfiGlobalVariableGuid, &Variable, &mVariableModuleGlobal->VariableGlobal, FALSE);\r
+ if (!EFI_ERROR (Status)) {\r
+ //\r
+ // Update PlatformLang\r
+ //\r
+ VariableName = EFI_LANG_VARIABLE_NAME;\r
+ Data = GetVariableDataPtr (Variable.CurrPtr);\r
+ DataSize = Variable.CurrPtr->DataSize;\r
+ } else {\r
+ //\r
+ // Neither PlatformLang nor Lang is set, directly return\r
+ //\r
+ return EFI_SUCCESS;\r
+ }\r
+ }\r
+ }\r
+\r
+ Status = EFI_SUCCESS;\r
+\r
+ //\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, EFI_PLATFORM_LANG_VARIABLE_NAME) == 0) {\r
+ //\r
+ // Update Lang when PlatformLangCodes/LangCodes were set.\r
+ //\r
+ if ((mVariableModuleGlobal->PlatformLangCodes != NULL) && (mVariableModuleGlobal->LangCodes != NULL)) {\r
+ //\r
+ // When setting PlatformLang, firstly get most matched language string from supported language codes.\r
+ //\r
+ BestPlatformLang = VariableGetBestLanguage (mVariableModuleGlobal->PlatformLangCodes, FALSE, Data, NULL);\r
+ if (BestPlatformLang != NULL) {\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 RFC4646 language tag.\r
+ //\r
+ BestLang = GetLangFromSupportedLangCodes (mVariableModuleGlobal->LangCodes, Index, TRUE);\r
+\r
+ //\r
+ // Check the variable space for both Lang and PlatformLang variable.\r
+ //\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
+ }\r
+\r
+ DEBUG ((EFI_D_INFO, "Variable Driver Auto Update PlatformLang, PlatformLang:%a, Lang:%a Status: %r\n", BestPlatformLang, BestLang, Status));\r
+ }\r
+ }\r
+\r
+ } else if (StrCmp (VariableName, EFI_LANG_VARIABLE_NAME) == 0) {\r
+ //\r
+ // Update PlatformLang when PlatformLangCodes/LangCodes were set.\r
+ //\r
+ if ((mVariableModuleGlobal->PlatformLangCodes != NULL) && (mVariableModuleGlobal->LangCodes != NULL)) {\r
+ //\r
+ // When setting Lang, firstly get most matched language string from supported language codes.\r
+ //\r
+ BestLang = VariableGetBestLanguage (mVariableModuleGlobal->LangCodes, TRUE, Data, NULL);\r
+ if (BestLang != NULL) {\r
+ //\r
+ // Get the corresponding index in language codes.\r
+ //\r
+ Index = GetIndexFromSupportedLangCodes (mVariableModuleGlobal->LangCodes, BestLang, TRUE);\r
+\r
+ //\r
+ // Get the corresponding RFC4646 language tag according to ISO639 language tag.\r
+ //\r
+ BestPlatformLang = GetLangFromSupportedLangCodes (mVariableModuleGlobal->PlatformLangCodes, Index, FALSE);\r
+\r
+ //\r
+ // Check the variable space for both PlatformLang and Lang variable.\r
+ //\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
+ }\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
+ 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
+ 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
+ @param[in] VendorGuid Guid of variable.\r
+ @param[in] Data Variable data.\r
+ @param[in] DataSize Size of data. 0 means delete.\r
+ @param[in] Attributes Attribues of the variable.\r
+ @param[in, out] CacheVariable The variable information which is used to keep track of variable usage.\r
+ \r
+ @retval EFI_SUCCESS The update operation is success.\r
+ @retval EFI_OUT_OF_RESOURCES Variable region is full, can not write other data into this region.\r
+\r
+**/\r
+EFI_STATUS\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 OUT VARIABLE_POINTER_TRACK *CacheVariable\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ VARIABLE_HEADER *NextVariable;\r
+ UINTN ScratchSize;\r
+ UINTN NonVolatileVarableStoreSize;\r
+ UINTN VarNameOffset;\r
+ UINTN VarDataOffset;\r
+ UINTN VarNameSize;\r
+ UINTN VarSize;\r
+ BOOLEAN Volatile;\r
+ EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *Fvb;\r
+ UINT8 State;\r
+ VARIABLE_POINTER_TRACK *Variable;\r
+ VARIABLE_POINTER_TRACK NvVariable;\r
+ VARIABLE_STORE_HEADER *VariableStoreHeader;\r
+ UINTN CacheOffset;\r
+\r
+ if ((mVariableModuleGlobal->FvbInstance == NULL) && ((Attributes & EFI_VARIABLE_NON_VOLATILE) != 0)) {\r
+ //\r
+ // The FVB protocol is not ready. Trying to update NV variable prior to the installation\r
+ // of EFI_VARIABLE_WRITE_ARCH_PROTOCOL.\r
+ //\r
+ return EFI_NOT_AVAILABLE_YET; \r
+ }\r
+\r
+ if ((CacheVariable->CurrPtr == NULL) || CacheVariable->Volatile) {\r
+ Variable = CacheVariable;\r
+ } else {\r
+ //\r
+ // Update/Delete existing NV variable.\r
+ // CacheVariable points to the variable in the memory copy of Flash area\r
+ // Now let Variable points to the same variable in Flash area.\r
+ //\r
+ VariableStoreHeader = (VARIABLE_STORE_HEADER *) ((UINTN) mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase);\r
+ Variable = &NvVariable; \r
+ Variable->StartPtr = GetStartPointer (VariableStoreHeader);\r
+ Variable->EndPtr = GetEndPointer (VariableStoreHeader);\r
+ Variable->CurrPtr = (VARIABLE_HEADER *)((UINTN)Variable->StartPtr + ((UINTN)CacheVariable->CurrPtr - (UINTN)CacheVariable->StartPtr));\r
+ if (CacheVariable->InDeletedTransitionPtr != NULL) {\r
+ Variable->InDeletedTransitionPtr = (VARIABLE_HEADER *)((UINTN)Variable->StartPtr + ((UINTN)CacheVariable->InDeletedTransitionPtr - (UINTN)CacheVariable->StartPtr));\r
+ } else {\r
+ Variable->InDeletedTransitionPtr = NULL;\r
+ }\r
+ Variable->Volatile = FALSE;\r
+ } \r
+\r
+ Fvb = mVariableModuleGlobal->FvbInstance;\r
+\r
+ if (Variable->CurrPtr != NULL) {\r
+ //\r
+ // Update/Delete existing variable.\r
+ //\r
+ if (AtRuntime ()) { \r
+ //\r
+ // If AtRuntime 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 that have NV|RT attributes can be updated/deleted in Runtime.\r
+ //\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
+ }\r
+\r
+ //\r
+ // Setting a data variable with no access, or zero DataSize attributes\r
+ // causes it to be deleted.\r
+ //\r
+ if (DataSize == 0 || (Attributes & (EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS)) == 0) { \r
+ if (Variable->InDeletedTransitionPtr != NULL) {\r
+ //\r
+ // Both ADDED and IN_DELETED_TRANSITION variable are present,\r
+ // set IN_DELETED_TRANSITION one to DELETED state first.\r
+ //\r
+ State = Variable->InDeletedTransitionPtr->State;\r
+ State &= VAR_DELETED;\r
+ Status = UpdateVariableStore (\r
+ &mVariableModuleGlobal->VariableGlobal,\r
+ Variable->Volatile,\r
+ FALSE,\r
+ Fvb,\r
+ (UINTN) &Variable->InDeletedTransitionPtr->State,\r
+ sizeof (UINT8),\r
+ &State\r
+ );\r
+ if (!EFI_ERROR (Status)) {\r
+ if (!Variable->Volatile) {\r
+ ASSERT (CacheVariable->InDeletedTransitionPtr != NULL);\r
+ CacheVariable->InDeletedTransitionPtr->State = State;\r
+ }\r
+ } else {\r
+ goto Done;\r
+ }\r
+ }\r
+\r
+ State = Variable->CurrPtr->State;\r
+ State &= VAR_DELETED;\r
+\r
+ Status = UpdateVariableStore (\r
+ &mVariableModuleGlobal->VariableGlobal,\r
+ Variable->Volatile,\r
+ FALSE,\r
+ Fvb,\r
+ (UINTN) &Variable->CurrPtr->State,\r
+ sizeof (UINT8),\r
+ &State\r
+ ); \r
+ if (!EFI_ERROR (Status)) {\r
+ UpdateVariableInfo (VariableName, VendorGuid, Variable->Volatile, FALSE, FALSE, TRUE, FALSE);\r
+ if (!Variable->Volatile) {\r
+ CacheVariable->CurrPtr->State = State;\r
+ FlushHobVariableToFlash (VariableName, VendorGuid);\r
+ }\r
+ }\r
+ goto Done; \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 (DataSizeOfVariable (Variable->CurrPtr) == DataSize &&\r
+ (CompareMem (Data, GetVariableDataPtr (Variable->CurrPtr), DataSize) == 0)) {\r
+ \r
+ UpdateVariableInfo (VariableName, VendorGuid, Variable->Volatile, FALSE, TRUE, FALSE, FALSE);\r
+ Status = EFI_SUCCESS;\r
+ goto Done;\r
+ } else if ((Variable->CurrPtr->State == VAR_ADDED) ||\r
+ (Variable->CurrPtr->State == (VAR_ADDED & VAR_IN_DELETED_TRANSITION))) {\r
+\r
+ //\r
+ // Mark the old variable as in delete transition.\r
+ //\r
+ State = Variable->CurrPtr->State;\r
+ State &= VAR_IN_DELETED_TRANSITION;\r
+\r
+ Status = UpdateVariableStore (\r
+ &mVariableModuleGlobal->VariableGlobal,\r
+ Variable->Volatile,\r
+ FALSE,\r
+ Fvb,\r
+ (UINTN) &Variable->CurrPtr->State,\r
+ sizeof (UINT8),\r
+ &State\r
+ ); \r
+ if (EFI_ERROR (Status)) {\r
+ goto Done; \r
+ } \r
+ if (!Variable->Volatile) {\r
+ CacheVariable->CurrPtr->State = State;\r
+ }\r
+ } \r
+ } else {\r
+ //\r
+ // Not 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 zero DataSize or no access 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 (AtRuntime () &&\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
+ // Tricky part: Use scratch data area at the end of volatile variable store\r
+ // as a temporary storage.\r
+ //\r
+ NextVariable = GetEndPointer ((VARIABLE_STORE_HEADER *) ((UINTN) mVariableModuleGlobal->VariableGlobal.VolatileVariableBase));\r
+ ScratchSize = MAX (PcdGet32 (PcdMaxVariableSize), PcdGet32 (PcdMaxHardwareErrorVariableSize));\r
+\r
+ SetMem (NextVariable, ScratchSize, 0xff);\r
+\r
+ NextVariable->StartId = VARIABLE_DATA;\r
+ NextVariable->Attributes = Attributes;\r
+ //\r
+ // NextVariable->State = VAR_ADDED;\r
+ //\r
+ NextVariable->Reserved = 0;\r
+ VarNameOffset = sizeof (VARIABLE_HEADER);\r
+ VarNameSize = StrSize (VariableName);\r
+ CopyMem (\r
+ (UINT8 *) ((UINTN) NextVariable + VarNameOffset),\r
+ VariableName,\r
+ VarNameSize\r
+ );\r
+ VarDataOffset = VarNameOffset + VarNameSize + GET_PAD_SIZE (VarNameSize);\r
+ CopyMem (\r
+ (UINT8 *) ((UINTN) NextVariable + VarDataOffset),\r
+ Data,\r
+ DataSize\r
+ );\r
+ CopyMem (&NextVariable->VendorGuid, VendorGuid, sizeof (EFI_GUID));\r
+ //\r
+ // There will be pad bytes after Data, the NextVariable->NameSize and\r
+ // NextVariable->DataSize should not include pad size so that variable\r
+ // service can get actual size in GetVariable.\r
+ //\r
+ NextVariable->NameSize = (UINT32)VarNameSize;\r
+ NextVariable->DataSize = (UINT32)DataSize;\r
+\r
+ //\r
+ // The actual size of the variable that stores in storage should\r
+ // include pad size.\r
+ //\r
+ VarSize = VarDataOffset + DataSize + GET_PAD_SIZE (DataSize);\r
+ if ((Attributes & EFI_VARIABLE_NON_VOLATILE) != 0) {\r
+ //\r
+ // Create a nonvolatile variable.\r
+ //\r
+ Volatile = FALSE;\r
+ NonVolatileVarableStoreSize = ((VARIABLE_STORE_HEADER *)(UINTN)(mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase))->Size;\r
+ if ((((Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) != 0) \r
+ && ((VarSize + mVariableModuleGlobal->HwErrVariableTotalSize) > PcdGet32 (PcdHwErrStorageSize)))\r
+ || (((Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == 0) \r
+ && ((VarSize + mVariableModuleGlobal->CommonVariableTotalSize) > NonVolatileVarableStoreSize - sizeof (VARIABLE_STORE_HEADER) - PcdGet32 (PcdHwErrStorageSize)))) {\r
+ if (AtRuntime ()) {\r
+ Status = EFI_OUT_OF_RESOURCES;\r
+ goto Done;\r
+ }\r
+ //\r
+ // Perform garbage collection & reclaim operation, and integrate the new variable at the same time.\r
+ //\r
+ Status = Reclaim (mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase, \r
+ &mVariableModuleGlobal->NonVolatileLastVariableOffset, FALSE, Variable, NextVariable, HEADER_ALIGN (VarSize));\r
+ if (!EFI_ERROR (Status)) {\r
+ //\r
+ // The new variable has been integrated successfully during reclaiming.\r
+ //\r
+ if (Variable->CurrPtr != NULL) {\r
+ CacheVariable->CurrPtr = (VARIABLE_HEADER *)((UINTN) CacheVariable->StartPtr + ((UINTN) Variable->CurrPtr - (UINTN) Variable->StartPtr));\r
+ CacheVariable->InDeletedTransitionPtr = NULL;\r
+ }\r
+ UpdateVariableInfo (VariableName, VendorGuid, FALSE, FALSE, TRUE, FALSE, FALSE);\r
+ FlushHobVariableToFlash (VariableName, VendorGuid);\r
+ }\r
+ goto Done;\r
+ }\r
+ //\r
+ // Four steps\r
+ // 1. Write variable header\r
+ // 2. Set variable state to header valid \r
+ // 3. Write variable data\r
+ // 4. Set variable state to valid\r
+ //\r
+ //\r
+ // Step 1:\r
+ //\r
+ CacheOffset = mVariableModuleGlobal->NonVolatileLastVariableOffset;\r
+ Status = UpdateVariableStore (\r
+ &mVariableModuleGlobal->VariableGlobal,\r
+ FALSE,\r
+ TRUE,\r
+ Fvb,\r
+ mVariableModuleGlobal->NonVolatileLastVariableOffset,\r
+ sizeof (VARIABLE_HEADER),\r
+ (UINT8 *) NextVariable\r
+ );\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ goto Done;\r
+ }\r
+\r
+ //\r
+ // Step 2:\r
+ //\r
+ NextVariable->State = VAR_HEADER_VALID_ONLY;\r
+ Status = UpdateVariableStore (\r
+ &mVariableModuleGlobal->VariableGlobal,\r
+ FALSE,\r
+ TRUE,\r
+ Fvb,\r
+ mVariableModuleGlobal->NonVolatileLastVariableOffset + OFFSET_OF (VARIABLE_HEADER, State),\r
+ sizeof (UINT8),\r
+ &NextVariable->State\r
+ );\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ goto Done;\r
+ }\r
+ //\r
+ // Step 3:\r
+ //\r
+ Status = UpdateVariableStore (\r
+ &mVariableModuleGlobal->VariableGlobal,\r
+ FALSE,\r
+ TRUE,\r
+ Fvb,\r
+ mVariableModuleGlobal->NonVolatileLastVariableOffset + sizeof (VARIABLE_HEADER),\r
+ (UINT32) VarSize - sizeof (VARIABLE_HEADER),\r
+ (UINT8 *) NextVariable + sizeof (VARIABLE_HEADER)\r
+ );\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ goto Done;\r
+ }\r
+ //\r
+ // Step 4:\r
+ //\r
+ NextVariable->State = VAR_ADDED;\r
+ Status = UpdateVariableStore (\r
+ &mVariableModuleGlobal->VariableGlobal,\r
+ FALSE,\r
+ TRUE,\r
+ Fvb,\r
+ mVariableModuleGlobal->NonVolatileLastVariableOffset + OFFSET_OF (VARIABLE_HEADER, State),\r
+ sizeof (UINT8),\r
+ &NextVariable->State\r
+ );\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ goto Done;\r
+ }\r
+\r
+ mVariableModuleGlobal->NonVolatileLastVariableOffset += HEADER_ALIGN (VarSize);\r
+\r
+ if ((Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) != 0) {\r
+ mVariableModuleGlobal->HwErrVariableTotalSize += HEADER_ALIGN (VarSize);\r
+ } else {\r
+ mVariableModuleGlobal->CommonVariableTotalSize += HEADER_ALIGN (VarSize);\r
+ }\r
+ //\r
+ // update the memory copy of Flash region.\r
+ //\r
+ CopyMem ((UINT8 *)mNvVariableCache + CacheOffset, (UINT8 *)NextVariable, VarSize);\r
+ } else {\r
+ //\r
+ // Create a volatile variable.\r
+ // \r
+ Volatile = TRUE;\r
+\r
+ if ((UINT32) (VarSize + mVariableModuleGlobal->VolatileLastVariableOffset) >\r
+ ((VARIABLE_STORE_HEADER *) ((UINTN) (mVariableModuleGlobal->VariableGlobal.VolatileVariableBase)))->Size) {\r
+ //\r
+ // Perform garbage collection & reclaim operation, and integrate the new variable at the same time.\r
+ //\r
+ Status = Reclaim (mVariableModuleGlobal->VariableGlobal.VolatileVariableBase, \r
+ &mVariableModuleGlobal->VolatileLastVariableOffset, TRUE, Variable, NextVariable, HEADER_ALIGN (VarSize));\r
+ if (!EFI_ERROR (Status)) {\r
+ //\r
+ // The new variable has been integrated successfully during reclaiming.\r
+ //\r
+ if (Variable->CurrPtr != NULL) {\r
+ CacheVariable->CurrPtr = (VARIABLE_HEADER *)((UINTN) CacheVariable->StartPtr + ((UINTN) Variable->CurrPtr - (UINTN) Variable->StartPtr));\r
+ CacheVariable->InDeletedTransitionPtr = NULL;\r
+ }\r
+ UpdateVariableInfo (VariableName, VendorGuid, TRUE, FALSE, TRUE, FALSE, FALSE);\r
+ }\r
+ goto Done;\r
+ }\r
+\r
+ NextVariable->State = VAR_ADDED;\r
+ Status = UpdateVariableStore (\r
+ &mVariableModuleGlobal->VariableGlobal,\r
+ TRUE,\r
+ TRUE,\r
+ Fvb,\r
+ mVariableModuleGlobal->VolatileLastVariableOffset,\r
+ (UINT32) VarSize,\r
+ (UINT8 *) NextVariable\r
+ );\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ goto Done;\r
+ }\r
+\r
+ mVariableModuleGlobal->VolatileLastVariableOffset += HEADER_ALIGN (VarSize);\r
+ }\r
+\r
+ //\r
+ // Mark the old variable as deleted.\r
+ //\r
+ if (!EFI_ERROR (Status) && Variable->CurrPtr != NULL) {\r
+ if (Variable->InDeletedTransitionPtr != NULL) {\r
+ //\r
+ // Both ADDED and IN_DELETED_TRANSITION old variable are present,\r
+ // set IN_DELETED_TRANSITION one to DELETED state first.\r
+ //\r
+ State = Variable->InDeletedTransitionPtr->State;\r
+ State &= VAR_DELETED;\r
+ Status = UpdateVariableStore (\r
+ &mVariableModuleGlobal->VariableGlobal,\r
+ Variable->Volatile,\r
+ FALSE,\r
+ Fvb,\r
+ (UINTN) &Variable->InDeletedTransitionPtr->State,\r
+ sizeof (UINT8),\r
+ &State\r
+ );\r
+ if (!EFI_ERROR (Status)) {\r
+ if (!Variable->Volatile) {\r
+ ASSERT (CacheVariable->InDeletedTransitionPtr != NULL);\r
+ CacheVariable->InDeletedTransitionPtr->State = State;\r
+ }\r
+ } else {\r
+ goto Done;\r
+ }\r
+ }\r
+\r
+ State = Variable->CurrPtr->State;\r
+ State &= VAR_DELETED;\r
+\r
+ Status = UpdateVariableStore (\r
+ &mVariableModuleGlobal->VariableGlobal,\r
+ Variable->Volatile,\r
+ FALSE,\r
+ Fvb,\r
+ (UINTN) &Variable->CurrPtr->State,\r
+ sizeof (UINT8),\r
+ &State\r
+ );\r
+ if (!EFI_ERROR (Status) && !Variable->Volatile) { \r
+ CacheVariable->CurrPtr->State = State;\r
+ }\r
+ }\r
+\r
+ if (!EFI_ERROR (Status)) {\r
+ UpdateVariableInfo (VariableName, VendorGuid, Volatile, FALSE, TRUE, FALSE, FALSE);\r
+ if (!Volatile) {\r
+ FlushHobVariableToFlash (VariableName, VendorGuid);\r
+ }\r
+ }\r
+\r
+Done:\r
+ 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
+ This code checks if variable guid is global variable guid first.\r
+ If yes, further check if variable name is in mGlobalVariableList or mGlobalVariableList2 and attributes matched.\r
+\r
+ @param[in] VariableName Pointer to variable name.\r
+ @param[in] VendorGuid Variable Vendor Guid.\r
+ @param[in] Attributes Attributes of the variable.\r
+\r
+ @retval EFI_SUCCESS Variable is not global variable, or Variable is global variable, variable name is in the lists and attributes matched.\r
+ @retval EFI_INVALID_PARAMETER Variable is global variable, but variable name is not in the lists or attributes unmatched.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+CheckEfiGlobalVariable (\r
+ IN CHAR16 *VariableName,\r
+ IN EFI_GUID *VendorGuid,\r
+ IN UINT32 Attributes\r
+ )\r
+{\r
+ UINTN Index;\r
+ UINTN NameLength;\r
+\r
+ if (CompareGuid (VendorGuid, &gEfiGlobalVariableGuid)){\r
+ //\r
+ // Try list 1, exactly match.\r
+ //\r
+ for (Index = 0; Index < sizeof (mGlobalVariableList)/sizeof (mGlobalVariableList[0]); Index++) {\r
+ if ((StrCmp (mGlobalVariableList[Index].Name, VariableName) == 0) &&\r
+ (Attributes == 0 || Attributes == mGlobalVariableList[Index].Attributes)) {\r
+ return EFI_SUCCESS;\r
+ }\r
+ }\r
+\r
+ //\r
+ // Try list 2.\r
+ //\r
+ NameLength = StrLen (VariableName) - 4;\r
+ for (Index = 0; Index < sizeof (mGlobalVariableList2)/sizeof (mGlobalVariableList2[0]); Index++) {\r
+ if ((StrLen (VariableName) == StrLen (mGlobalVariableList2[Index].Name)) &&\r
+ (StrnCmp (mGlobalVariableList2[Index].Name, VariableName, NameLength) == 0) &&\r
+ IsHexaDecimalDigitCharacter (VariableName[NameLength]) &&\r
+ IsHexaDecimalDigitCharacter (VariableName[NameLength + 1]) &&\r
+ IsHexaDecimalDigitCharacter (VariableName[NameLength + 2]) &&\r
+ IsHexaDecimalDigitCharacter (VariableName[NameLength + 3]) &&\r
+ (Attributes == 0 || Attributes == mGlobalVariableList2[Index].Attributes)) {\r
+ return EFI_SUCCESS;\r
+ }\r
+ }\r
+\r
+ DEBUG ((EFI_D_INFO, "[Variable]: set global variable with invalid variable name or attributes - %g:%s:%x\n", VendorGuid, VariableName, Attributes));\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Mark a variable that will become read-only after leaving the DXE phase of execution.\r
+\r
+ @param[in] This The VARIABLE_LOCK_PROTOCOL instance.\r
+ @param[in] VariableName A pointer to the variable name that will be made read-only subsequently.\r
+ @param[in] VendorGuid A pointer to the vendor GUID that will be made read-only subsequently.\r
+\r
+ @retval EFI_SUCCESS The variable specified by the VariableName and the VendorGuid was marked\r
+ as pending to be read-only.\r
+ @retval EFI_INVALID_PARAMETER VariableName or VendorGuid is NULL.\r
+ Or VariableName is an empty string.\r
+ @retval EFI_ACCESS_DENIED EFI_END_OF_DXE_EVENT_GROUP_GUID or EFI_EVENT_GROUP_READY_TO_BOOT has\r
+ already been signaled.\r
+ @retval EFI_OUT_OF_RESOURCES There is not enough resource to hold the lock request.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+VariableLockRequestToLock (\r
+ IN CONST EDKII_VARIABLE_LOCK_PROTOCOL *This,\r
+ IN CHAR16 *VariableName,\r
+ IN EFI_GUID *VendorGuid\r
+ )\r
+{\r
+ VARIABLE_ENTRY *Entry;\r
+\r
+ if (VariableName == NULL || VariableName[0] == 0 || VendorGuid == NULL) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r