+ // 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