From 72399daee45430942ac39d5807c96f544a09d9dc Mon Sep 17 00:00:00 2001 From: eric_tian Date: Mon, 27 Apr 2009 07:06:01 +0000 Subject: update platformlangcodes and langcodes to adapt new language convert algorithm. git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@8184 6f19259b-4bc3-4df7-8a09-765794883524 --- .../Universal/Variable/EmuRuntimeDxe/EmuVariable.c | 756 +++++++++++++---- .../EmuRuntimeDxe/EmuVariableRuntimeDxe.inf | 2 + .../Variable/EmuRuntimeDxe/InitVariable.c | 12 +- .../Universal/Variable/EmuRuntimeDxe/Variable.h | 26 +- .../Universal/Variable/RuntimeDxe/Variable.c | 932 ++++++++++++++------- .../Universal/Variable/RuntimeDxe/Variable.h | 4 + .../Variable/RuntimeDxe/VariableRuntimeDxe.inf | 3 + 7 files changed, 1239 insertions(+), 496 deletions(-) (limited to 'MdeModulePkg') diff --git a/MdeModulePkg/Universal/Variable/EmuRuntimeDxe/EmuVariable.c b/MdeModulePkg/Universal/Variable/EmuRuntimeDxe/EmuVariable.c index 21a689734b..1fb886accc 100644 --- a/MdeModulePkg/Universal/Variable/EmuRuntimeDxe/EmuVariable.c +++ b/MdeModulePkg/Universal/Variable/EmuRuntimeDxe/EmuVariable.c @@ -23,6 +23,73 @@ ESAL_VARIABLE_GLOBAL *mVariableModuleGlobal; VARIABLE_INFO_ENTRY *gVariableInfo = NULL; +/// +/// The size of a 3 character ISO639 language code. +/// +#define ISO_639_2_ENTRY_SIZE 3 + +/** + Update the variable region with Variable information. These are the same + arguments as the EFI Variable services. + + @param[in] VariableName Name of variable + + @param[in] VendorGuid Guid of variable + + @param[in] Data Variable data + + @param[in] DataSize Size of data. 0 means delete + + @param[in] Attributes Attribues of the variable + + @param[in] Variable The variable information which is used to keep track of variable usage. + + @retval EFI_SUCCESS The update operation is success. + + @retval EFI_OUT_OF_RESOURCES Variable region is full, can not write other data into this region. + +**/ +EFI_STATUS +EFIAPI +UpdateVariable ( + IN CHAR16 *VariableName, + IN EFI_GUID *VendorGuid, + IN VOID *Data, + IN UINTN DataSize, + IN UINT32 Attributes OPTIONAL, + IN VARIABLE_POINTER_TRACK *Variable + ); + +/** + Finds variable in storage blocks of volatile and non-volatile storage areas. + + This code finds variable in storage blocks of volatile and non-volatile storage areas. + If VariableName is an empty string, then we just return the first + qualified variable without comparing VariableName and VendorGuid. + Otherwise, VariableName and VendorGuid are compared. + + @param VariableName Name of the variable to be found. + @param VendorGuid Vendor GUID to be found. + @param PtrTrack VARIABLE_POINTER_TRACK structure for output, + including the range searched and the target position. + @param Global Pointer to VARIABLE_GLOBAL structure, including + base of volatile variable storage area, base of + NV variable storage area, and a lock. + + @retval EFI_INVALID_PARAMETER If VariableName is not an empty string, while + VendorGuid is NULL. + @retval EFI_SUCCESS Variable successfully found. + @retval EFI_NOT_FOUND Variable not found. + +**/ +EFI_STATUS +FindVariable ( + IN CHAR16 *VariableName, + IN EFI_GUID *VendorGuid, + OUT VARIABLE_POINTER_TRACK *PtrTrack, + IN VARIABLE_GLOBAL *Global + ); + /** Acquires lock only at boot time. Simply returns at runtime. @@ -118,9 +185,7 @@ GetNextVariablePtr ( // VarHeader = (VARIABLE_HEADER *) (GetVariableDataPtr (Variable) + Variable->DataSize + GET_PAD_SIZE (Variable->DataSize)); - if (VarHeader->StartId != VARIABLE_DATA || - (sizeof (VARIABLE_HEADER) + VarHeader->DataSize + VarHeader->NameSize) > FixedPcdGet32(PcdMaxVariableSize) - ) { + if (VarHeader->StartId != VARIABLE_DATA) { return NULL; } @@ -246,6 +311,472 @@ UpdateVariableInfo ( } } +/** + Get index from supported language codes according to language string. + + This code is used to get corresponding index in supported language codes. It can handle + RFC3066 and ISO639 language tags. + In ISO639 language tags, take 3-characters as a delimitation to find matched string and calculate the index. + In RFC3066 language tags, take semicolon as a delimitation to find matched string and calculate the index. + + For example: + SupportedLang = "engfraengfra" + Lang = "eng" + Iso639Language = TRUE + The return value is "0". + Another example: + SupportedLang = "en;fr;en-US;fr-FR" + Lang = "fr-FR" + Iso639Language = FALSE + The return value is "3". + + @param SupportedLang Platform supported language codes. + @param Lang Configured language. + @param Iso639Language A bool value to signify if the handler is operated on ISO639 or RFC3066. + + @retval the index of language in the language codes. + +**/ +UINTN +EFIAPI +GetIndexFromSupportedLangCodes( + IN CHAR8 *SupportedLang, + IN CHAR8 *Lang, + IN BOOLEAN Iso639Language + ) +{ + UINTN Index; + UINT32 CompareLength; + CHAR8 *Supported; + + Index = 0; + Supported = SupportedLang; + if (Iso639Language) { + CompareLength = 3; + for (Index = 0; Index < AsciiStrLen (SupportedLang); Index += CompareLength) { + if (AsciiStrnCmp (Lang, SupportedLang + Index, CompareLength) == 0) { + // + // Successfully find the index of Lang string in SupportedLang string. + // + Index = Index / CompareLength; + return Index; + } + } + ASSERT (FALSE); + return 0; + } else { + // + // Compare RFC3066 language code + // + while (*Supported != '\0') { + // + // take semicolon as delimitation, sequentially traverse supported language codes. + // + for (CompareLength = 0; *Supported != ';' && *Supported != '\0'; CompareLength++) { + Supported++; + } + if (AsciiStrnCmp (Lang, Supported - CompareLength, CompareLength) == 0) { + // + // Successfully find the index of Lang string in SupportedLang string. + // + return Index; + } + Index++; + } + ASSERT (FALSE); + return 0; + } +} + +/** + Get language string from supported language codes according to index. + + This code is used to get corresponding language string in supported language codes. It can handle + RFC3066 and ISO639 language tags. + In ISO639 language tags, take 3-characters as a delimitation. Find language string according to the index. + In RFC3066 language tags, take semicolon as a delimitation. Find language string according to the index. + + For example: + SupportedLang = "engfraengfra" + Index = "1" + Iso639Language = TRUE + The return value is "fra". + Another example: + SupportedLang = "en;fr;en-US;fr-FR" + Index = "1" + Iso639Language = FALSE + The return value is "fr". + + @param SupportedLang Platform supported language codes. + @param Index the index in supported language codes. + @param Iso639Language A bool value to signify if the handler is operated on ISO639 or RFC3066. + + @retval the language string in the language codes. + +**/ +CHAR8 * +EFIAPI +GetLangFromSupportedLangCodes ( + IN CHAR8 *SupportedLang, + IN UINTN Index, + IN BOOLEAN Iso639Language +) +{ + UINTN SubIndex; + UINT32 CompareLength; + CHAR8 *Supported; + + SubIndex = 0; + Supported = SupportedLang; + if (Iso639Language) { + // + // according to the index of Lang string in SupportedLang string to get the language. + // As this code will be invoked in RUNTIME, therefore there is not memory allocate/free operation. + // In driver entry, it pre-allocates a runtime attribute memory to accommodate this string. + // + CompareLength = 3; + SetMem (mVariableModuleGlobal->Lang, sizeof(mVariableModuleGlobal->Lang), 0); + return CopyMem (mVariableModuleGlobal->Lang, SupportedLang + Index * CompareLength, CompareLength); + + } else { + while (TRUE) { + // + // take semicolon as delimitation, sequentially traverse supported language codes. + // + for (CompareLength = 0; *Supported != ';' && *Supported != '\0'; CompareLength++) { + Supported++; + } + if ((*Supported == '\0') && (SubIndex != Index)) { + // + // Have completed the traverse, but not find corrsponding string. + // This case is not allowed to happen. + // + ASSERT(FALSE); + return NULL; + } + if (SubIndex == Index) { + // + // according to the index of Lang string in SupportedLang string to get the language. + // As this code will be invoked in RUNTIME, therefore there is not memory allocate/free operation. + // In driver entry, it pre-allocates a runtime attribute memory to accommodate this string. + // + SetMem (mVariableModuleGlobal->PlatformLang, sizeof (mVariableModuleGlobal->PlatformLang), 0); + return CopyMem (mVariableModuleGlobal->PlatformLang, Supported - CompareLength, CompareLength); + } + SubIndex++; + } + } +} + +/** + Hook the operations in PlatformLangCodes, LangCodes, PlatformLang and Lang. + + When setting Lang/LangCodes, simultaneously update PlatformLang/PlatformLangCodes. + + According to UEFI spec, PlatformLangCodes/LangCodes are only set once in firmware initialization, + and are read-only. Therefore, in variable driver, only store the original value for other use. + + @param[in] VariableName Name of variable + + @param[in] Data Variable data + + @param[in] DataSize Size of data. 0 means delete + + @retval EFI_SUCCESS auto update operation is successful. + +**/ +EFI_STATUS +EFIAPI +AutoUpdateLangVariable( + IN CHAR16 *VariableName, + IN VOID *Data, + IN UINTN DataSize + ) +{ + EFI_STATUS Status; + CHAR8 *BestPlatformLang; + CHAR8 *BestLang; + UINTN Index; + UINT32 Attributes; + VARIABLE_POINTER_TRACK Variable; + + // + // According to UEFI spec, "Lang" and "PlatformLang" is NV|BS|RT attributions. + // + Attributes = EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS; + + if (StrCmp (VariableName, L"PlatformLangCodes") == 0) { + // + // According to UEFI spec, PlatformLangCodes is only set once in firmware initialization, and is read-only + // Therefore, in variable driver, only store the original value for other use. + // + AsciiStrnCpy (mVariableModuleGlobal->PlatformLangCodes, Data, DataSize); + } else if (StrCmp (VariableName, L"LangCodes") == 0) { + // + // According to UEFI spec, LangCodes is only set once in firmware initialization, and is read-only + // Therefore, in variable driver, only store the original value for other use. + // + AsciiStrnCpy (mVariableModuleGlobal->LangCodes, Data, DataSize); + } else if (StrCmp (VariableName, L"PlatformLang") == 0) { + ASSERT (AsciiStrLen (mVariableModuleGlobal->PlatformLangCodes) != 0); + + // + // When setting PlatformLang, firstly get most matched language string from supported language codes. + // + BestPlatformLang = GetBestLanguage(mVariableModuleGlobal->PlatformLangCodes, FALSE, Data); + + // + // Get the corresponding index in language codes. + // + Index = GetIndexFromSupportedLangCodes(mVariableModuleGlobal->PlatformLangCodes, BestPlatformLang, FALSE); + + // + // Get the corresponding ISO639 language tag according to RFC3066 language tag. + // + BestLang = GetLangFromSupportedLangCodes(mVariableModuleGlobal->LangCodes, Index, TRUE); + + // + // Successfully convert PlatformLang to Lang, and set the BestLang value into Lang variable simultaneously. + // + FindVariable(L"Lang", &gEfiGlobalVariableGuid, &Variable, (VARIABLE_GLOBAL *)mVariableModuleGlobal); + + Status = UpdateVariable(L"Lang", &gEfiGlobalVariableGuid, + BestLang, ISO_639_2_ENTRY_SIZE + 1, Attributes, &Variable); + + DEBUG((EFI_D_INFO, "Variable Driver Auto Update PlatformLang, PlatformLang:%a, Lang:%a\n", BestPlatformLang, BestLang)); + + ASSERT_EFI_ERROR(Status); + + } else if (StrCmp (VariableName, L"Lang") == 0) { + ASSERT (AsciiStrLen (mVariableModuleGlobal->LangCodes) != 0); + + // + // When setting Lang, firstly get most matched language string from supported language codes. + // + BestLang = GetBestLanguage(mVariableModuleGlobal->LangCodes, TRUE, Data); + + // + // Get the corresponding index in language codes. + // + Index = GetIndexFromSupportedLangCodes(mVariableModuleGlobal->LangCodes, BestLang, TRUE); + + // + // Get the corresponding RFC3066 language tag according to ISO639 language tag. + // + BestPlatformLang = GetLangFromSupportedLangCodes(mVariableModuleGlobal->PlatformLangCodes, Index, FALSE); + + // + // Successfully convert Lang to PlatformLang, and set the BestPlatformLang value into PlatformLang variable simultaneously. + // + FindVariable(L"PlatformLang", &gEfiGlobalVariableGuid, &Variable, (VARIABLE_GLOBAL *)mVariableModuleGlobal); + + Status = UpdateVariable(L"PlatformLang", &gEfiGlobalVariableGuid, + BestPlatformLang, AsciiStrLen (BestPlatformLang), Attributes, &Variable); + + DEBUG((EFI_D_INFO, "Variable Driver Auto Update Lang, Lang:%a, PlatformLang:%a\n", BestLang, BestPlatformLang)); + ASSERT_EFI_ERROR(Status); + } + return EFI_SUCCESS; +} + +/** + Update the variable region with Variable information. These are the same + arguments as the EFI Variable services. + + @param[in] VariableName Name of variable + + @param[in] VendorGuid Guid of variable + + @param[in] Data Variable data + + @param[in] DataSize Size of data. 0 means delete + + @param[in] Attributes Attribues of the variable + + @param[in] Variable The variable information which is used to keep track of variable usage. + + @retval EFI_SUCCESS The update operation is success. + + @retval EFI_OUT_OF_RESOURCES Variable region is full, can not write other data into this region. + +**/ +EFI_STATUS +EFIAPI +UpdateVariable ( + IN CHAR16 *VariableName, + IN EFI_GUID *VendorGuid, + IN VOID *Data, + IN UINTN DataSize, + IN UINT32 Attributes OPTIONAL, + IN VARIABLE_POINTER_TRACK *Variable + ) +{ + EFI_STATUS Status; + VARIABLE_HEADER *NextVariable; + UINTN VarNameSize; + UINTN VarNameOffset; + UINTN VarDataOffset; + UINTN VarSize; + VARIABLE_GLOBAL *Global; + UINTN NonVolatileVarableStoreSize; + + Global = &mVariableModuleGlobal->VariableGlobal[Physical]; + + if (Variable->CurrPtr != NULL) { + // + // Update/Delete existing variable + // + + if (EfiAtRuntime ()) { + // + // If EfiAtRuntime and the variable is Volatile and Runtime Access, + // the volatile is ReadOnly, and SetVariable should be aborted and + // return EFI_WRITE_PROTECTED. + // + if (Variable->Volatile) { + Status = EFI_WRITE_PROTECTED; + goto Done; + } + // + // Only variable have NV attribute can be updated/deleted in Runtime + // + if ((Variable->CurrPtr->Attributes & EFI_VARIABLE_NON_VOLATILE) == 0) { + Status = EFI_INVALID_PARAMETER; + goto Done; + } + } + + // + // Setting a data variable with no access, or zero DataSize attributes + // specified causes it to be deleted. + // + if (DataSize == 0 || (Attributes & (EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS)) == 0) { + Variable->CurrPtr->State &= VAR_DELETED; + UpdateVariableInfo (VariableName, VendorGuid, Variable->Volatile, FALSE, FALSE, TRUE, FALSE); + Status = EFI_SUCCESS; + goto Done; + } + + // + // If the variable is marked valid and the same data has been passed in + // then return to the caller immediately. + // + if (Variable->CurrPtr->DataSize == DataSize && + CompareMem (Data, GetVariableDataPtr (Variable->CurrPtr), DataSize) == 0 + ) { + Status = EFI_SUCCESS; + goto Done; + } else if (Variable->CurrPtr->State == VAR_ADDED) { + // + // Mark the old variable as in delete transition + // + Variable->CurrPtr->State &= VAR_IN_DELETED_TRANSITION; + } + + } else { + // + // No found existing variable, Create a new variable + // + + // + // Make sure we are trying to create a new variable. + // Setting a data variable with no access, or zero DataSize attributes means to delete it. + // + if (DataSize == 0 || (Attributes & (EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS)) == 0) { + Status = EFI_NOT_FOUND; + goto Done; + } + + // + // Only variable have NV|RT attribute can be created in Runtime + // + if (EfiAtRuntime () && + (((Attributes & EFI_VARIABLE_RUNTIME_ACCESS) == 0) || ((Attributes & EFI_VARIABLE_NON_VOLATILE) == 0))) { + Status = EFI_INVALID_PARAMETER; + goto Done; + } + } + + // + // Function part - create a new variable and copy the data. + // Both update a variable and create a variable will come here. + // + + VarNameOffset = sizeof (VARIABLE_HEADER); + VarNameSize = StrSize (VariableName); + VarDataOffset = VarNameOffset + VarNameSize + GET_PAD_SIZE (VarNameSize); + VarSize = VarDataOffset + DataSize + GET_PAD_SIZE (DataSize); + + if ((Attributes & EFI_VARIABLE_NON_VOLATILE) != 0) { + NonVolatileVarableStoreSize = ((VARIABLE_STORE_HEADER *)(UINTN)(Global->NonVolatileVariableBase))->Size; + if ((((Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) != 0) + && ((VarSize + mVariableModuleGlobal->HwErrVariableTotalSize) > FixedPcdGet32(PcdHwErrStorageSize))) + || (((Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == 0) + && ((VarSize + mVariableModuleGlobal->CommonVariableTotalSize) > NonVolatileVarableStoreSize - sizeof (VARIABLE_STORE_HEADER) - FixedPcdGet32(PcdHwErrStorageSize)))) { + Status = EFI_OUT_OF_RESOURCES; + goto Done; + } + + NextVariable = (VARIABLE_HEADER *) (UINT8 *) (mVariableModuleGlobal->NonVolatileLastVariableOffset + + (UINTN) Global->NonVolatileVariableBase); + mVariableModuleGlobal->NonVolatileLastVariableOffset += VarSize; + + if ((Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) != 0) { + mVariableModuleGlobal->HwErrVariableTotalSize += VarSize; + } else { + mVariableModuleGlobal->CommonVariableTotalSize += VarSize; + } + } else { + if ((UINT32) (VarSize + mVariableModuleGlobal->VolatileLastVariableOffset) > + ((VARIABLE_STORE_HEADER *) ((UINTN) (Global->VolatileVariableBase)))->Size + ) { + Status = EFI_OUT_OF_RESOURCES; + goto Done; + } + + NextVariable = (VARIABLE_HEADER *) (UINT8 *) (mVariableModuleGlobal->VolatileLastVariableOffset + + (UINTN) Global->VolatileVariableBase); + mVariableModuleGlobal->VolatileLastVariableOffset += VarSize; + } + + NextVariable->StartId = VARIABLE_DATA; + NextVariable->Attributes = Attributes; + NextVariable->State = VAR_ADDED; + NextVariable->Reserved = 0; + + // + // There will be pad bytes after Data, the NextVariable->NameSize and + // NextVariable->NameSize should not include pad size so that variable + // service can get actual size in GetVariable + // + NextVariable->NameSize = (UINT32)VarNameSize; + NextVariable->DataSize = (UINT32)DataSize; + + CopyMem (&NextVariable->VendorGuid, VendorGuid, sizeof (EFI_GUID)); + CopyMem ( + (UINT8 *) ((UINTN) NextVariable + VarNameOffset), + VariableName, + VarNameSize + ); + CopyMem ( + (UINT8 *) ((UINTN) NextVariable + VarDataOffset), + Data, + DataSize + ); + + // + // Mark the old variable as deleted + // + Variable->CurrPtr->State &= VAR_DELETED; + + UpdateVariableInfo (VariableName, VendorGuid, Variable->Volatile, FALSE, TRUE, FALSE, FALSE); + + Status = EFI_SUCCESS; + +Done: + return Status; +} + /** Finds variable in storage blocks of volatile and non-volatile storage areas. @@ -349,7 +880,6 @@ FindVariable ( @param Data On input, the size in bytes of the return Data buffer. On output, the size of data returned in Data. @param Global Pointer to VARIABLE_GLOBAL structure - @param Instance Instance of the Firmware Volume. @retval EFI_SUCCESS The function completed successfully. @retval EFI_NOT_FOUND The variable was not found. @@ -362,12 +892,11 @@ EFI_STATUS EFIAPI EmuGetVariable ( IN CHAR16 *VariableName, - IN EFI_GUID * VendorGuid, + IN EFI_GUID *VendorGuid, OUT UINT32 *Attributes OPTIONAL, IN OUT UINTN *DataSize, OUT VOID *Data, - IN VARIABLE_GLOBAL * Global, - IN UINT32 Instance + IN VARIABLE_GLOBAL *Global ) { VARIABLE_POINTER_TRACK Variable; @@ -425,7 +954,6 @@ Done: @param VendorGuid On input, supplies the last VendorGuid that was returned by GetNextVariableName(). On output, returns the VendorGuid of the current variable. @param Global Pointer to VARIABLE_GLOBAL structure. - @param Instance Instance of the Firmware Volume. @retval EFI_SUCCESS The function completed successfully. @retval EFI_NOT_FOUND The next variable was not found. @@ -440,8 +968,7 @@ EmuGetNextVariableName ( IN OUT UINTN *VariableNameSize, IN OUT CHAR16 *VariableName, IN OUT EFI_GUID *VendorGuid, - IN VARIABLE_GLOBAL *Global, - IN UINT32 Instance + IN VARIABLE_GLOBAL *Global ) { VARIABLE_POINTER_TRACK Variable; @@ -535,7 +1062,6 @@ Done: @param Global Pointer to VARIABLE_GLOBAL structure @param VolatileOffset The offset of last volatile variable @param NonVolatileOffset The offset of last non-volatile variable - @param Instance Instance of the Firmware Volume. @retval EFI_SUCCESS The firmware has successfully stored the variable and its data as defined by the Attributes. @@ -558,17 +1084,11 @@ EmuSetVariable ( IN VOID *Data, IN VARIABLE_GLOBAL *Global, IN UINTN *VolatileOffset, - IN UINTN *NonVolatileOffset, - IN UINT32 Instance + IN UINTN *NonVolatileOffset ) { VARIABLE_POINTER_TRACK Variable; EFI_STATUS Status; - VARIABLE_HEADER *NextVariable; - UINTN VarNameSize; - UINTN VarNameOffset; - UINTN VarDataOffset; - UINTN VarSize; // // Check input parameters @@ -608,155 +1128,13 @@ EmuSetVariable ( Status = FindVariable (VariableName, VendorGuid, &Variable, Global); - if (Status == EFI_SUCCESS && Variable.CurrPtr != NULL) { - // - // Update/Delete existing variable - // - - if (EfiAtRuntime ()) { - // - // If EfiAtRuntime and the variable is Volatile and Runtime Access, - // the volatile is ReadOnly, and SetVariable should be aborted and - // return EFI_WRITE_PROTECTED. - // - if (Variable.Volatile) { - Status = EFI_WRITE_PROTECTED; - goto Done; - } - // - // Only variable have NV attribute can be updated/deleted in Runtime - // - if ((Variable.CurrPtr->Attributes & EFI_VARIABLE_NON_VOLATILE) == 0) { - Status = EFI_INVALID_PARAMETER; - goto Done; - } - } - - // - // Setting a data variable with no access, or zero DataSize attributes - // specified causes it to be deleted. - // - if (DataSize == 0 || (Attributes & (EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS)) == 0) { - Variable.CurrPtr->State &= VAR_DELETED; - UpdateVariableInfo (VariableName, VendorGuid, Variable.Volatile, FALSE, FALSE, TRUE, FALSE); - Status = EFI_SUCCESS; - goto Done; - } - - // - // If the variable is marked valid and the same data has been passed in - // then return to the caller immediately. - // - if (Variable.CurrPtr->DataSize == DataSize && - CompareMem (Data, GetVariableDataPtr (Variable.CurrPtr), DataSize) == 0 - ) { - Status = EFI_SUCCESS; - goto Done; - } else if (Variable.CurrPtr->State == VAR_ADDED) { - // - // Mark the old variable as in delete transition - // - Variable.CurrPtr->State &= VAR_IN_DELETED_TRANSITION; - } - - } else if (Status == EFI_NOT_FOUND) { - // - // Create a new variable - // - - // - // Make sure we are trying to create a new variable. - // Setting a data variable with no access, or zero DataSize attributes means to delete it. - // - if (DataSize == 0 || (Attributes & (EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS)) == 0) { - Status = EFI_NOT_FOUND; - goto Done; - } - - // - // Only variable have NV|RT attribute can be created in Runtime - // - if (EfiAtRuntime () && - (((Attributes & EFI_VARIABLE_RUNTIME_ACCESS) == 0) || ((Attributes & EFI_VARIABLE_NON_VOLATILE) == 0))) { - Status = EFI_INVALID_PARAMETER; - goto Done; - } - } else { - // - // Status should be EFI_INVALID_PARAMETER here according to return status of FindVariable(). - // - ASSERT (Status == EFI_INVALID_PARAMETER); - goto Done; - } - // - // Function part - create a new variable and copy the data. - // Both update a variable and create a variable will come here. + // Hook the operation of setting PlatformLangCodes/PlatformLang and LangCodes/Lang // - - VarNameOffset = sizeof (VARIABLE_HEADER); - VarNameSize = StrSize (VariableName); - VarDataOffset = VarNameOffset + VarNameSize + GET_PAD_SIZE (VarNameSize); - VarSize = VarDataOffset + DataSize + GET_PAD_SIZE (DataSize); + AutoUpdateLangVariable (VariableName, Data, DataSize); - if ((Attributes & EFI_VARIABLE_NON_VOLATILE) != 0) { - if ((UINT32) (VarSize +*NonVolatileOffset) > - ((VARIABLE_STORE_HEADER *) ((UINTN) (Global->NonVolatileVariableBase)))->Size - ) { - Status = EFI_OUT_OF_RESOURCES; - goto Done; - } + Status = UpdateVariable (VariableName, VendorGuid, Data, DataSize, Attributes, &Variable); - NextVariable = (VARIABLE_HEADER *) (UINT8 *) (*NonVolatileOffset + (UINTN) Global->NonVolatileVariableBase); - *NonVolatileOffset = *NonVolatileOffset + VarSize; - } else { - if ((UINT32) (VarSize +*VolatileOffset) > - ((VARIABLE_STORE_HEADER *) ((UINTN) (Global->VolatileVariableBase)))->Size - ) { - Status = EFI_OUT_OF_RESOURCES; - goto Done; - } - - NextVariable = (VARIABLE_HEADER *) (UINT8 *) (*VolatileOffset + (UINTN) Global->VolatileVariableBase); - *VolatileOffset = *VolatileOffset + VarSize; - } - - NextVariable->StartId = VARIABLE_DATA; - NextVariable->Attributes = Attributes; - NextVariable->State = VAR_ADDED; - NextVariable->Reserved = 0; - - // - // There will be pad bytes after Data, the NextVariable->NameSize and - // NextVariable->NameSize should not include pad size so that variable - // service can get actual size in GetVariable - // - NextVariable->NameSize = (UINT32)VarNameSize; - NextVariable->DataSize = (UINT32)DataSize; - - CopyMem (&NextVariable->VendorGuid, VendorGuid, sizeof (EFI_GUID)); - CopyMem ( - (UINT8 *) ((UINTN) NextVariable + VarNameOffset), - VariableName, - VarNameSize - ); - CopyMem ( - (UINT8 *) ((UINTN) NextVariable + VarDataOffset), - Data, - DataSize - ); - - // - // Mark the old variable as deleted - // - if (!EFI_ERROR (Status)) { - Variable.CurrPtr->State &= VAR_DELETED; - } - - UpdateVariableInfo (VariableName, VendorGuid, Variable.Volatile, FALSE, TRUE, FALSE, FALSE); - - Status = EFI_SUCCESS; -Done: ReleaseLockOnlyAtBootTime (&Global->VariableServicesLock); return Status; } @@ -774,7 +1152,6 @@ Done: @param MaximumVariableSize Returns the maximum size of an individual EFI variable associated with the attributes specified. @param Global Pointer to VARIABLE_GLOBAL structure. - @param Instance Instance of the Firmware Volume. @retval EFI_SUCCESS Valid answer returned. @retval EFI_INVALID_PARAMETER An invalid combination of attribute bits was supplied @@ -790,14 +1167,18 @@ EmuQueryVariableInfo ( OUT UINT64 *MaximumVariableStorageSize, OUT UINT64 *RemainingVariableStorageSize, OUT UINT64 *MaximumVariableSize, - IN VARIABLE_GLOBAL *Global, - IN UINT32 Instance + IN VARIABLE_GLOBAL *Global ) { VARIABLE_HEADER *Variable; VARIABLE_HEADER *NextVariable; UINT64 VariableSize; VARIABLE_STORE_HEADER *VariableStoreHeader; + UINT64 CommonVariableTotalSize; + UINT64 HwErrVariableTotalSize; + + CommonVariableTotalSize = 0; + HwErrVariableTotalSize = 0; if(MaximumVariableStorageSize == NULL || RemainingVariableStorageSize == NULL || MaximumVariableSize == NULL || Attributes == 0) { return EFI_INVALID_PARAMETER; @@ -818,6 +1199,11 @@ EmuQueryVariableInfo ( // Make sure RT Attribute is set if we are in Runtime phase. // return EFI_INVALID_PARAMETER; + } else if ((Attributes & (EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_HARDWARE_ERROR_RECORD)) == EFI_VARIABLE_HARDWARE_ERROR_RECORD) { + // + // Make sure Hw Attribute is set with NV. + // + return EFI_INVALID_PARAMETER; } AcquireLockOnlyAtBootTime(&Global->VariableServicesLock); @@ -839,18 +1225,23 @@ EmuQueryVariableInfo ( // with the storage size (excluding the storage header size) // *MaximumVariableStorageSize = VariableStoreHeader->Size - sizeof (VARIABLE_STORE_HEADER); - *RemainingVariableStorageSize = VariableStoreHeader->Size - sizeof (VARIABLE_STORE_HEADER); - - // - // Let *MaximumVariableSize be FixedPcdGet32(PcdMaxVariableSize) with the exception of the variable header size. - // - *MaximumVariableSize = FixedPcdGet32(PcdMaxVariableSize) - sizeof (VARIABLE_HEADER); // // Harware error record variable needs larger size. // - if ((Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == EFI_VARIABLE_HARDWARE_ERROR_RECORD) { + if ((Attributes & (EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_HARDWARE_ERROR_RECORD)) == (EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_HARDWARE_ERROR_RECORD)) { + *MaximumVariableStorageSize = FixedPcdGet32(PcdHwErrStorageSize); *MaximumVariableSize = FixedPcdGet32(PcdMaxHardwareErrorVariableSize) - sizeof (VARIABLE_HEADER); + } else { + if ((Attributes & EFI_VARIABLE_NON_VOLATILE) != 0) { + ASSERT (FixedPcdGet32(PcdHwErrStorageSize) < VariableStoreHeader->Size); + *MaximumVariableStorageSize = VariableStoreHeader->Size - sizeof (VARIABLE_STORE_HEADER) - FixedPcdGet32(PcdHwErrStorageSize); + } + + // + // Let *MaximumVariableSize be FixedPcdGet32(PcdMaxVariableSize) with the exception of the variable header size. + // + *MaximumVariableSize = FixedPcdGet32(PcdMaxVariableSize) - sizeof (VARIABLE_HEADER); } // @@ -862,15 +1253,16 @@ EmuQueryVariableInfo ( // Now walk through the related variable store. // while (Variable < GetEndPointer (VariableStoreHeader)) { - if (Variable->StartId != VARIABLE_DATA) { + NextVariable = GetNextVariablePtr(Variable); + if (NextVariable == NULL) { break; } - - NextVariable = (VARIABLE_HEADER *) (GetVariableDataPtr (Variable) + Variable->DataSize + GET_PAD_SIZE (Variable->DataSize)); VariableSize = (UINT64) (UINTN) NextVariable - (UINT64) (UINTN) Variable; - if (Variable->State == VAR_ADDED) { - *RemainingVariableStorageSize -= VariableSize; + if ((NextVariable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == EFI_VARIABLE_HARDWARE_ERROR_RECORD) { + HwErrVariableTotalSize += VariableSize; + } else { + CommonVariableTotalSize += VariableSize; } // @@ -879,6 +1271,12 @@ EmuQueryVariableInfo ( Variable = NextVariable; } + if ((Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == EFI_VARIABLE_HARDWARE_ERROR_RECORD){ + *RemainingVariableStorageSize = *MaximumVariableStorageSize - HwErrVariableTotalSize; + } else { + *RemainingVariableStorageSize = *MaximumVariableStorageSize - CommonVariableTotalSize; + } + if (*RemainingVariableStorageSize < sizeof (VARIABLE_HEADER)) { *MaximumVariableSize = 0; } else if ((*RemainingVariableStorageSize - sizeof (VARIABLE_HEADER)) < *MaximumVariableSize) { @@ -959,7 +1357,7 @@ VariableCommonInitialize ( // // Allocate memory for mVariableModuleGlobal // - mVariableModuleGlobal = (ESAL_VARIABLE_GLOBAL *) AllocateRuntimePool ( + mVariableModuleGlobal = (ESAL_VARIABLE_GLOBAL *) AllocateRuntimeZeroPool ( sizeof (ESAL_VARIABLE_GLOBAL) ); if (NULL == mVariableModuleGlobal) { diff --git a/MdeModulePkg/Universal/Variable/EmuRuntimeDxe/EmuVariableRuntimeDxe.inf b/MdeModulePkg/Universal/Variable/EmuRuntimeDxe/EmuVariableRuntimeDxe.inf index 4e9ebefc8a..4f7d06b3e6 100644 --- a/MdeModulePkg/Universal/Variable/EmuRuntimeDxe/EmuVariableRuntimeDxe.inf +++ b/MdeModulePkg/Universal/Variable/EmuRuntimeDxe/EmuVariableRuntimeDxe.inf @@ -56,6 +56,7 @@ [Guids] gEfiEventVirtualAddressChangeGuid ## PRODUCES ## Event + gEfiGlobalVariableGuid ## PRODUCES ## Variable Guid gEfiVariableGuid [Pcd.common] @@ -63,6 +64,7 @@ gEfiMdeModulePkgTokenSpaceGuid.PcdMaxHardwareErrorVariableSize gEfiMdeModulePkgTokenSpaceGuid.PcdVariableStoreSize gEfiMdeModulePkgTokenSpaceGuid.PcdVariableCollectStatistics + gEfiMdeModulePkgTokenSpaceGuid.PcdHwErrStorageSize [Depex] TRUE diff --git a/MdeModulePkg/Universal/Variable/EmuRuntimeDxe/InitVariable.c b/MdeModulePkg/Universal/Variable/EmuRuntimeDxe/InitVariable.c index fa2b2a32ba..b4ecf86862 100644 --- a/MdeModulePkg/Universal/Variable/EmuRuntimeDxe/InitVariable.c +++ b/MdeModulePkg/Universal/Variable/EmuRuntimeDxe/InitVariable.c @@ -51,8 +51,7 @@ RuntimeServiceGetVariable ( Attributes OPTIONAL, DataSize, Data, - &mVariableModuleGlobal->VariableGlobal[Physical], - mVariableModuleGlobal->FvbInstance + &mVariableModuleGlobal->VariableGlobal[Physical] ); } @@ -82,8 +81,7 @@ RuntimeServiceGetNextVariableName ( VariableNameSize, VariableName, VendorGuid, - &mVariableModuleGlobal->VariableGlobal[Physical], - mVariableModuleGlobal->FvbInstance + &mVariableModuleGlobal->VariableGlobal[Physical] ); } @@ -123,8 +121,7 @@ RuntimeServiceSetVariable ( Data, &mVariableModuleGlobal->VariableGlobal[Physical], &mVariableModuleGlobal->VolatileLastVariableOffset, - &mVariableModuleGlobal->NonVolatileLastVariableOffset, - mVariableModuleGlobal->FvbInstance + &mVariableModuleGlobal->NonVolatileLastVariableOffset ); } @@ -160,8 +157,7 @@ RuntimeServiceQueryVariableInfo ( MaximumVariableStorageSize, RemainingVariableStorageSize, MaximumVariableSize, - &mVariableModuleGlobal->VariableGlobal[Physical], - mVariableModuleGlobal->FvbInstance + &mVariableModuleGlobal->VariableGlobal[Physical] ); } diff --git a/MdeModulePkg/Universal/Variable/EmuRuntimeDxe/Variable.h b/MdeModulePkg/Universal/Variable/EmuRuntimeDxe/Variable.h index cd83e6c1f5..cc5803dde9 100644 --- a/MdeModulePkg/Universal/Variable/EmuRuntimeDxe/Variable.h +++ b/MdeModulePkg/Universal/Variable/EmuRuntimeDxe/Variable.h @@ -32,6 +32,7 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. #include #include #include +#include #include @@ -59,7 +60,12 @@ typedef struct { VARIABLE_GLOBAL VariableGlobal[2]; UINTN VolatileLastVariableOffset; UINTN NonVolatileLastVariableOffset; - UINT32 FvbInstance; + UINTN CommonVariableTotalSize; + UINTN HwErrVariableTotalSize; + CHAR8 PlatformLangCodes[256]; //Pre-allocate 256 bytes space to accommodate the PlatformlangCodes. + CHAR8 LangCodes[256]; //Pre-allocate 256 bytes space to accommodate the langCodes. + CHAR8 PlatformLang[8]; //Pre-allocate 8 bytes space to accommodate the Platformlang variable. + CHAR8 Lang[4]; //Pre-allocate 4 bytes space to accommodate the lang variable. } ESAL_VARIABLE_GLOBAL; /// @@ -138,7 +144,6 @@ VariableClassAddressChangeEvent ( @param Data On input, the size in bytes of the return Data buffer. On output, the size of data returned in Data. @param Global Pointer to VARIABLE_GLOBAL structure - @param Instance Instance of the Firmware Volume. @retval EFI_SUCCESS The function completed successfully. @retval EFI_NOT_FOUND The variable was not found. @@ -151,12 +156,11 @@ EFI_STATUS EFIAPI EmuGetVariable ( IN CHAR16 *VariableName, - IN EFI_GUID * VendorGuid, + IN EFI_GUID *VendorGuid, OUT UINT32 *Attributes OPTIONAL, IN OUT UINTN *DataSize, OUT VOID *Data, - IN VARIABLE_GLOBAL * Global, - IN UINT32 Instance + IN VARIABLE_GLOBAL *Global ); /** @@ -169,7 +173,6 @@ EmuGetVariable ( @param VendorGuid On input, supplies the last VendorGuid that was returned by GetNextVariableName(). On output, returns the VendorGuid of the current variable. @param Global Pointer to VARIABLE_GLOBAL structure. - @param Instance Instance of the Firmware Volume. @retval EFI_SUCCESS The function completed successfully. @retval EFI_NOT_FOUND The next variable was not found. @@ -184,8 +187,7 @@ EmuGetNextVariableName ( IN OUT UINTN *VariableNameSize, IN OUT CHAR16 *VariableName, IN OUT EFI_GUID *VendorGuid, - IN VARIABLE_GLOBAL *Global, - IN UINT32 Instance + IN VARIABLE_GLOBAL *Global ); /** @@ -205,7 +207,6 @@ EmuGetNextVariableName ( @param Global Pointer to VARIABLE_GLOBAL structure @param VolatileOffset The offset of last volatile variable @param NonVolatileOffset The offset of last non-volatile variable - @param Instance Instance of the Firmware Volume. @retval EFI_SUCCESS The firmware has successfully stored the variable and its data as defined by the Attributes. @@ -228,8 +229,7 @@ EmuSetVariable ( IN VOID *Data, IN VARIABLE_GLOBAL *Global, IN UINTN *VolatileOffset, - IN UINTN *NonVolatileOffset, - IN UINT32 Instance + IN UINTN *NonVolatileOffset ); /** @@ -245,7 +245,6 @@ EmuSetVariable ( @param MaximumVariableSize Returns the maximum size of an individual EFI variable associated with the attributes specified. @param Global Pointer to VARIABLE_GLOBAL structure. - @param Instance Instance of the Firmware Volume. @retval EFI_SUCCESS Valid answer returned. @retval EFI_INVALID_PARAMETER An invalid combination of attribute bits was supplied @@ -261,8 +260,7 @@ EmuQueryVariableInfo ( OUT UINT64 *MaximumVariableStorageSize, OUT UINT64 *RemainingVariableStorageSize, OUT UINT64 *MaximumVariableSize, - IN VARIABLE_GLOBAL *Global, - IN UINT32 Instance + IN VARIABLE_GLOBAL *Global ); #endif diff --git a/MdeModulePkg/Universal/Variable/RuntimeDxe/Variable.c b/MdeModulePkg/Universal/Variable/RuntimeDxe/Variable.c index 62025c9ee1..611d1904ec 100644 --- a/MdeModulePkg/Universal/Variable/RuntimeDxe/Variable.c +++ b/MdeModulePkg/Universal/Variable/RuntimeDxe/Variable.c @@ -19,6 +19,10 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. VARIABLE_MODULE_GLOBAL *mVariableModuleGlobal; EFI_EVENT mVirtualAddressChangeEvent = NULL; EFI_HANDLE mHandle = NULL; +/// +/// The size of a 3 character ISO639 language code. +/// +#define ISO_639_2_ENTRY_SIZE 3 /// /// The current Hii implementation accesses this variable many times on every boot. @@ -33,12 +37,50 @@ VARIABLE_CACHE_ENTRY mVariableCache[] = { 0x00000000, 0x00, NULL + }, + { + &gEfiGlobalVariableGuid, + L"PlatformLang", + 0x00000000, + 0x00, + NULL } }; -VARIABLE_INFO_ENTRY *gVariableInfo = NULL; -EFI_EVENT mFvbRegistration = NULL; +VARIABLE_INFO_ENTRY *gVariableInfo = NULL; +EFI_EVENT mFvbRegistration = NULL; + +/** + Update the variable region with Variable information. These are the same + arguments as the EFI Variable services. + + @param[in] VariableName Name of variable + + @param[in] VendorGuid Guid of variable + + @param[in] Data Variable data + + @param[in] DataSize Size of data. 0 means delete + + @param[in] Attributes Attribues of the variable + + @param[in] Variable The variable information which is used to keep track of variable usage. + @retval EFI_SUCCESS The update operation is success. + + @retval EFI_OUT_OF_RESOURCES Variable region is full, can not write other data into this region. + +**/ +EFI_STATUS +EFIAPI +UpdateVariable ( + IN CHAR16 *VariableName, + IN EFI_GUID *VendorGuid, + IN VOID *Data, + IN UINTN DataSize, + IN UINT32 Attributes OPTIONAL, + IN VARIABLE_POINTER_TRACK *Variable + ); /** Acquires lock only at boot time. Simply returns at runtime. @@ -1006,309 +1048,327 @@ FindVariable ( return EFI_NOT_FOUND; } - /** - - This code finds variable in storage blocks (Volatile or Non-Volatile). - - @param VariableName Name of Variable to be found. - @param VendorGuid Variable vendor GUID. - @param Attributes Attribute value of the variable found. - @param DataSize Size of Data found. If size is less than the - data, this value contains the required size. - @param Data Data pointer. - - @return EFI_INVALID_PARAMETER Invalid parameter - @return EFI_SUCCESS Find the specified variable - @return EFI_NOT_FOUND Not found - @return EFI_BUFFER_TO_SMALL DataSize is too small for the result + Get index from supported language codes according to language string. + + This code is used to get corresponding index in supported language codes. It can handle + RFC3066 and ISO639 language tags. + In ISO639 language tags, take 3-characters as a delimitation to find matched string and calculate the index. + In RFC3066 language tags, take semicolon as a delimitation to find matched string and calculate the index. + + For example: + SupportedLang = "engfraengfra" + Lang = "eng" + Iso639Language = TRUE + The return value is "0". + Another example: + SupportedLang = "en;fr;en-US;fr-FR" + Lang = "fr-FR" + Iso639Language = FALSE + The return value is "3". + + @param SupportedLang Platform supported language codes. + @param Lang Configured language. + @param Iso639Language A bool value to signify if the handler is operated on ISO639 or RFC3066. + + @retval the index of language in the language codes. **/ -EFI_STATUS +UINTN EFIAPI -RuntimeServiceGetVariable ( - IN CHAR16 *VariableName, - IN EFI_GUID *VendorGuid, - OUT UINT32 *Attributes OPTIONAL, - IN OUT UINTN *DataSize, - OUT VOID *Data - ) +GetIndexFromSupportedLangCodes( + IN CHAR8 *SupportedLang, + IN CHAR8 *Lang, + IN BOOLEAN Iso639Language + ) { - EFI_STATUS Status; - VARIABLE_POINTER_TRACK Variable; - UINTN VarDataSize; - - if (VariableName == NULL || VendorGuid == NULL || DataSize == NULL) { - return EFI_INVALID_PARAMETER; - } - - AcquireLockOnlyAtBootTime(&mVariableModuleGlobal->VariableGlobal.VariableServicesLock); - - // - // Find existing variable - // - Status = FindVariableInCache (VariableName, VendorGuid, Attributes, DataSize, Data); - if ((Status == EFI_BUFFER_TOO_SMALL) || (Status == EFI_SUCCESS)){ - // Hit in the Cache - UpdateVariableInfo (VariableName, VendorGuid, FALSE, TRUE, FALSE, FALSE, TRUE); - goto Done; - } - - Status = FindVariable (VariableName, VendorGuid, &Variable, &mVariableModuleGlobal->VariableGlobal); - if (Variable.CurrPtr == NULL || EFI_ERROR (Status)) { - goto Done; + UINTN Index; + UINT32 CompareLength; + CHAR8 *Supported; + + Index = 0; + Supported = SupportedLang; + if (Iso639Language) { + CompareLength = 3; + for (Index = 0; Index < AsciiStrLen (SupportedLang); Index += CompareLength) { + if (AsciiStrnCmp (Lang, SupportedLang + Index, CompareLength) == 0) { + // + // Successfully find the index of Lang string in SupportedLang string. + // + Index = Index / CompareLength; + return Index; + } + } + ASSERT (FALSE); + return 0; + } else { + // + // Compare RFC3066 language code + // + while (*Supported != '\0') { + // + // take semicolon as delimitation, sequentially traverse supported language codes. + // + for (CompareLength = 0; *Supported != ';' && *Supported != '\0'; CompareLength++) { + Supported++; + } + if (AsciiStrnCmp (Lang, Supported - CompareLength, CompareLength) == 0) { + // + // Successfully find the index of Lang string in SupportedLang string. + // + return Index; + } + Index++; + } + ASSERT (FALSE); + return 0; } +} - // - // Get data size - // - VarDataSize = DataSizeOfVariable (Variable.CurrPtr); - ASSERT (VarDataSize != 0); - - if (*DataSize >= VarDataSize) { - if (Data == NULL) { - Status = EFI_INVALID_PARAMETER; - goto Done; - } +/** + Get language string from supported language codes according to index. + + This code is used to get corresponding language string in supported language codes. It can handle + RFC3066 and ISO639 language tags. + In ISO639 language tags, take 3-characters as a delimitation. Find language string according to the index. + In RFC3066 language tags, take semicolon as a delimitation. Find language string according to the index. + + For example: + SupportedLang = "engfraengfra" + Index = "1" + Iso639Language = TRUE + The return value is "fra". + Another example: + SupportedLang = "en;fr;en-US;fr-FR" + Index = "1" + Iso639Language = FALSE + The return value is "fr". + + @param SupportedLang Platform supported language codes. + @param Index the index in supported language codes. + @param Iso639Language A bool value to signify if the handler is operated on ISO639 or RFC3066. + + @retval the language string in the language codes. - CopyMem (Data, GetVariableDataPtr (Variable.CurrPtr), VarDataSize); - if (Attributes != NULL) { - *Attributes = Variable.CurrPtr->Attributes; - } +**/ +CHAR8 * +EFIAPI +GetLangFromSupportedLangCodes ( + IN CHAR8 *SupportedLang, + IN UINTN Index, + IN BOOLEAN Iso639Language +) +{ + UINTN SubIndex; + UINT32 CompareLength; + CHAR8 *Supported; - *DataSize = VarDataSize; - UpdateVariableInfo (VariableName, VendorGuid, Variable.Volatile, TRUE, FALSE, FALSE, FALSE); - UpdateVariableCache (VariableName, VendorGuid, Variable.CurrPtr->Attributes, VarDataSize, Data); - - Status = EFI_SUCCESS; - goto Done; + SubIndex = 0; + Supported = SupportedLang; + if (Iso639Language) { + // + // according to the index of Lang string in SupportedLang string to get the language. + // As this code will be invoked in RUNTIME, therefore there is not memory allocate/free operation. + // In driver entry, it pre-allocates a runtime attribute memory to accommodate this string. + // + CompareLength = 3; + SetMem (mVariableModuleGlobal->Lang, sizeof(mVariableModuleGlobal->Lang), 0); + return CopyMem (mVariableModuleGlobal->Lang, SupportedLang + Index * CompareLength, CompareLength); + } else { - *DataSize = VarDataSize; - Status = EFI_BUFFER_TOO_SMALL; - goto Done; + while (TRUE) { + // + // take semicolon as delimitation, sequentially traverse supported language codes. + // + for (CompareLength = 0; *Supported != ';' && *Supported != '\0'; CompareLength++) { + Supported++; + } + if ((*Supported == '\0') && (SubIndex != Index)) { + // + // Have completed the traverse, but not find corrsponding string. + // This case is not allowed to happen. + // + ASSERT(FALSE); + return NULL; + } + if (SubIndex == Index) { + // + // according to the index of Lang string in SupportedLang string to get the language. + // As this code will be invoked in RUNTIME, therefore there is not memory allocate/free operation. + // In driver entry, it pre-allocates a runtime attribute memory to accommodate this string. + // + SetMem (mVariableModuleGlobal->PlatformLang, sizeof (mVariableModuleGlobal->PlatformLang), 0); + return CopyMem (mVariableModuleGlobal->PlatformLang, Supported - CompareLength, CompareLength); + } + SubIndex++; + } } - -Done: - ReleaseLockOnlyAtBootTime (&mVariableModuleGlobal->VariableGlobal.VariableServicesLock); - return Status; } +/** + Hook the operations in PlatformLangCodes, LangCodes, PlatformLang and Lang. + When setting Lang/LangCodes, simultaneously update PlatformLang/PlatformLangCodes. -/** + According to UEFI spec, PlatformLangCodes/LangCodes are only set once in firmware initialization, + and are read-only. Therefore, in variable driver, only store the original value for other use. - This code Finds the Next available variable. + @param[in] VariableName Name of variable - @param VariableNameSize Size of the variable name - @param VariableName Pointer to variable name - @param VendorGuid Variable Vendor Guid + @param[in] Data Variable data - @return EFI_INVALID_PARAMETER Invalid parameter - @return EFI_SUCCESS Find the specified variable - @return EFI_NOT_FOUND Not found - @return EFI_BUFFER_TO_SMALL DataSize is too small for the result + @param[in] DataSize Size of data. 0 means delete + + @retval EFI_SUCCESS auto update operation is successful. **/ EFI_STATUS EFIAPI -RuntimeServiceGetNextVariableName ( - IN OUT UINTN *VariableNameSize, - IN OUT CHAR16 *VariableName, - IN OUT EFI_GUID *VendorGuid +AutoUpdateLangVariable( + IN CHAR16 *VariableName, + IN VOID *Data, + IN UINTN DataSize ) { - VARIABLE_POINTER_TRACK Variable; - UINTN VarNameSize; - EFI_STATUS Status; + EFI_STATUS Status; + CHAR8 *BestPlatformLang; + CHAR8 *BestLang; + UINTN Index; + UINT32 Attributes; + VARIABLE_POINTER_TRACK Variable; - if (VariableNameSize == NULL || VariableName == NULL || VendorGuid == NULL) { - return EFI_INVALID_PARAMETER; - } + // + // According to UEFI spec, "Lang" and "PlatformLang" is NV|BS|RT attributions. + // + Attributes = EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS; - AcquireLockOnlyAtBootTime(&mVariableModuleGlobal->VariableGlobal.VariableServicesLock); + if (StrCmp (VariableName, L"PlatformLangCodes") == 0) { + // + // According to UEFI spec, PlatformLangCodes is only set once in firmware initialization, and is read-only + // Therefore, in variable driver, only store the original value for other use. + // + AsciiStrnCpy (mVariableModuleGlobal->PlatformLangCodes, Data, DataSize); + } else if (StrCmp (VariableName, L"LangCodes") == 0) { + // + // According to UEFI spec, LangCodes is only set once in firmware initialization, and is read-only + // Therefore, in variable driver, only store the original value for other use. + // + AsciiStrnCpy (mVariableModuleGlobal->LangCodes, Data, DataSize); + } else if (StrCmp (VariableName, L"PlatformLang") == 0) { + ASSERT (AsciiStrLen (mVariableModuleGlobal->PlatformLangCodes) != 0); - Status = FindVariable (VariableName, VendorGuid, &Variable, &mVariableModuleGlobal->VariableGlobal); - if (Variable.CurrPtr == NULL || EFI_ERROR (Status)) { - goto Done; - } + // + // When setting PlatformLang, firstly get most matched language string from supported language codes. + // + BestPlatformLang = GetBestLanguage(mVariableModuleGlobal->PlatformLangCodes, FALSE, Data); - if (VariableName[0] != 0) { // - // If variable name is not NULL, get next variable + // Get the corresponding index in language codes. // - Variable.CurrPtr = GetNextVariablePtr (Variable.CurrPtr); - } + Index = GetIndexFromSupportedLangCodes(mVariableModuleGlobal->PlatformLangCodes, BestPlatformLang, FALSE); - while (TRUE) { // - // If both volatile and non-volatile variable store are parsed, - // return not found + // Get the corresponding ISO639 language tag according to RFC3066 language tag. // - if (Variable.CurrPtr >= Variable.EndPtr || Variable.CurrPtr == NULL) { - Variable.Volatile = (BOOLEAN) (Variable.Volatile ^ ((BOOLEAN) 0x1)); - if (!Variable.Volatile) { - Variable.StartPtr = GetStartPointer ((VARIABLE_STORE_HEADER *) (UINTN) mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase); - Variable.EndPtr = GetEndPointer ((VARIABLE_STORE_HEADER *) ((UINTN) mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase)); - } else { - Status = EFI_NOT_FOUND; - goto Done; - } + BestLang = GetLangFromSupportedLangCodes(mVariableModuleGlobal->LangCodes, Index, TRUE); - Variable.CurrPtr = Variable.StartPtr; - if (!IsValidVariableHeader (Variable.CurrPtr)) { - continue; - } - } // - // Variable is found + // Successfully convert PlatformLang to Lang, and set the BestLang value into Lang variable simultaneously. // - if (IsValidVariableHeader (Variable.CurrPtr) && Variable.CurrPtr->State == VAR_ADDED) { - if ((EfiAtRuntime () && ((Variable.CurrPtr->Attributes & EFI_VARIABLE_RUNTIME_ACCESS) == 0)) == 0) { - VarNameSize = NameSizeOfVariable (Variable.CurrPtr); - ASSERT (VarNameSize != 0); + FindVariable(L"Lang", &gEfiGlobalVariableGuid, &Variable, (VARIABLE_GLOBAL *)mVariableModuleGlobal); - if (VarNameSize <= *VariableNameSize) { - CopyMem ( - VariableName, - GetVariableNamePtr (Variable.CurrPtr), - VarNameSize - ); - CopyMem ( - VendorGuid, - &Variable.CurrPtr->VendorGuid, - sizeof (EFI_GUID) - ); - Status = EFI_SUCCESS; - } else { - Status = EFI_BUFFER_TOO_SMALL; - } + Status = UpdateVariable(L"Lang", &gEfiGlobalVariableGuid, + BestLang, ISO_639_2_ENTRY_SIZE + 1, Attributes, &Variable); - *VariableNameSize = VarNameSize; - goto Done; - } - } + DEBUG((EFI_D_INFO, "Variable Driver Auto Update PlatformLang, PlatformLang:%a, Lang:%a\n", BestPlatformLang, BestLang)); - Variable.CurrPtr = GetNextVariablePtr (Variable.CurrPtr); - } + ASSERT_EFI_ERROR(Status); + + } else if (StrCmp (VariableName, L"Lang") == 0) { + ASSERT (AsciiStrLen (mVariableModuleGlobal->LangCodes) != 0); -Done: - ReleaseLockOnlyAtBootTime (&mVariableModuleGlobal->VariableGlobal.VariableServicesLock); - return Status; + // + // When setting Lang, firstly get most matched language string from supported language codes. + // + BestLang = GetBestLanguage(mVariableModuleGlobal->LangCodes, TRUE, Data); + + // + // Get the corresponding index in language codes. + // + Index = GetIndexFromSupportedLangCodes(mVariableModuleGlobal->LangCodes, BestLang, TRUE); + + // + // Get the corresponding RFC3066 language tag according to ISO639 language tag. + // + BestPlatformLang = GetLangFromSupportedLangCodes(mVariableModuleGlobal->PlatformLangCodes, Index, FALSE); + + // + // Successfully convert Lang to PlatformLang, and set the BestPlatformLang value into PlatformLang variable simultaneously. + // + FindVariable(L"PlatformLang", &gEfiGlobalVariableGuid, &Variable, (VARIABLE_GLOBAL *)mVariableModuleGlobal); + + Status = UpdateVariable(L"PlatformLang", &gEfiGlobalVariableGuid, + BestPlatformLang, AsciiStrLen (BestPlatformLang), Attributes, &Variable); + + DEBUG((EFI_D_INFO, "Variable Driver Auto Update Lang, Lang:%a, PlatformLang:%a\n", BestLang, BestPlatformLang)); + ASSERT_EFI_ERROR(Status); + } + return EFI_SUCCESS; } /** + Update the variable region with Variable information. These are the same + arguments as the EFI Variable services. - This code sets variable in storage blocks (Volatile or Non-Volatile). + @param[in] VariableName Name of variable - @param VariableName Name of Variable to be found - @param VendorGuid Variable vendor GUID - @param Attributes Attribute value of the variable found - @param DataSize Size of Data found. If size is less than the - data, this value contains the required size. - @param Data Data pointer + @param[in] VendorGuid Guid of variable - @return EFI_INVALID_PARAMETER Invalid parameter - @return EFI_SUCCESS Set successfully - @return EFI_OUT_OF_RESOURCES Resource not enough to set variable - @return EFI_NOT_FOUND Not found - @return EFI_WRITE_PROTECTED Variable is read-only + @param[in] Data Variable data + + @param[in] DataSize Size of data. 0 means delete + + @param[in] Attributes Attribues of the variable + + @param[in] Variable The variable information which is used to keep track of variable usage. + + @retval EFI_SUCCESS The update operation is success. + + @retval EFI_OUT_OF_RESOURCES Variable region is full, can not write other data into this region. **/ EFI_STATUS EFIAPI -RuntimeServiceSetVariable ( - IN CHAR16 *VariableName, - IN EFI_GUID *VendorGuid, - IN UINT32 Attributes, - IN UINTN DataSize, - IN VOID *Data +UpdateVariable ( + IN CHAR16 *VariableName, + IN EFI_GUID *VendorGuid, + IN VOID *Data, + IN UINTN DataSize, + IN UINT32 Attributes OPTIONAL, + IN VARIABLE_POINTER_TRACK *Variable ) { - VARIABLE_POINTER_TRACK Variable; EFI_STATUS Status; VARIABLE_HEADER *NextVariable; - UINTN VarNameSize; + UINTN ScratchSize; + UINTN NonVolatileVarableStoreSize; UINTN VarNameOffset; UINTN VarDataOffset; + UINTN VarNameSize; UINTN VarSize; + BOOLEAN Volatile; + EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *Fvb; UINT8 State; BOOLEAN Reclaimed; - UINTN *VolatileOffset; - UINTN *NonVolatileOffset; - EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *Fvb; - BOOLEAN Volatile; - EFI_PHYSICAL_ADDRESS Point; - UINTN ScratchSize; - UINTN NonVolatileVarableStoreSize; - - // - // Check input parameters - // - if (VariableName == NULL || VariableName[0] == 0 || VendorGuid == NULL) { - return EFI_INVALID_PARAMETER; - } - // - // Make sure if runtime bit is set, boot service bit is set also - // - if ((Attributes & (EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS)) == EFI_VARIABLE_RUNTIME_ACCESS) { - return EFI_INVALID_PARAMETER; - } - // - // The size of the VariableName, including the Unicode Null in bytes plus - // the DataSize is limited to maximum size of FixedPcdGet32(PcdMaxHardwareErrorVariableSize) - // bytes for HwErrRec, and FixedPcdGet32(PcdMaxVariableSize) bytes for the others. - // - if ((Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == EFI_VARIABLE_HARDWARE_ERROR_RECORD) { - if ((DataSize > FixedPcdGet32(PcdMaxHardwareErrorVariableSize)) || - (sizeof (VARIABLE_HEADER) + StrSize (VariableName) + DataSize > FixedPcdGet32(PcdMaxHardwareErrorVariableSize))) { - return EFI_INVALID_PARAMETER; - } - } else { - // - // The size of the VariableName, including the Unicode Null in bytes plus - // the DataSize is limited to maximum size of FixedPcdGet32(PcdMaxVariableSize) bytes. - // - if ((DataSize > FixedPcdGet32(PcdMaxVariableSize)) || - (sizeof (VARIABLE_HEADER) + StrSize (VariableName) + DataSize > FixedPcdGet32(PcdMaxVariableSize))) { - return EFI_INVALID_PARAMETER; - } - } - - AcquireLockOnlyAtBootTime(&mVariableModuleGlobal->VariableGlobal.VariableServicesLock); - - Reclaimed = FALSE; Fvb = mVariableModuleGlobal->FvbInstance; - VolatileOffset = &mVariableModuleGlobal->VolatileLastVariableOffset; - - // - // Consider reentrant in MCA/INIT/NMI. It needs be reupdated; - // - if (1 < InterlockedIncrement (&mVariableModuleGlobal->VariableGlobal.ReentrantState)) { - Point = mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase;; - // - // Parse non-volatile variable data and get last variable offset - // - NextVariable = GetStartPointer ((VARIABLE_STORE_HEADER *) (UINTN) Point); - while (IsValidVariableHeader (NextVariable)) { - NextVariable = GetNextVariablePtr (NextVariable); - } - mVariableModuleGlobal->NonVolatileLastVariableOffset = (UINTN) NextVariable - (UINTN) Point; - } - - NonVolatileOffset = &mVariableModuleGlobal->NonVolatileLastVariableOffset; - + Reclaimed = FALSE; - // - // Check whether the input variable is already existed - // - - Status = FindVariable (VariableName, VendorGuid, &Variable, &mVariableModuleGlobal->VariableGlobal); - if (Status == EFI_SUCCESS && Variable.CurrPtr != NULL) { + if (Variable->CurrPtr != NULL) { // // Update/Delete existing variable // - Volatile = Variable.Volatile; + Volatile = Variable->Volatile; if (EfiAtRuntime ()) { // @@ -1316,14 +1376,14 @@ RuntimeServiceSetVariable ( // the volatile is ReadOnly, and SetVariable should be aborted and // return EFI_WRITE_PROTECTED. // - if (Variable.Volatile) { + if (Variable->Volatile) { Status = EFI_WRITE_PROTECTED; goto Done; } // // Only variable have NV attribute can be updated/deleted in Runtime // - if ((Variable.CurrPtr->Attributes & EFI_VARIABLE_NON_VOLATILE) == 0) { + if ((Variable->CurrPtr->Attributes & EFI_VARIABLE_NON_VOLATILE) == 0) { Status = EFI_INVALID_PARAMETER; goto Done; } @@ -1333,15 +1393,15 @@ RuntimeServiceSetVariable ( // specified causes it to be deleted. // if (DataSize == 0 || (Attributes & (EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS)) == 0) { - State = Variable.CurrPtr->State; + State = Variable->CurrPtr->State; State &= VAR_DELETED; Status = UpdateVariableStore ( &mVariableModuleGlobal->VariableGlobal, - Variable.Volatile, + Variable->Volatile, FALSE, Fvb, - (UINTN) &Variable.CurrPtr->State, + (UINTN) &Variable->CurrPtr->State, sizeof (UINT8), &State ); @@ -1355,27 +1415,27 @@ RuntimeServiceSetVariable ( // If the variable is marked valid and the same data has been passed in // then return to the caller immediately. // - if (DataSizeOfVariable (Variable.CurrPtr) == DataSize && - (CompareMem (Data, GetVariableDataPtr (Variable.CurrPtr), DataSize) == 0)) { + if (DataSizeOfVariable (Variable->CurrPtr) == DataSize && + (CompareMem (Data, GetVariableDataPtr (Variable->CurrPtr), DataSize) == 0)) { UpdateVariableInfo (VariableName, VendorGuid, Volatile, FALSE, TRUE, FALSE, FALSE); Status = EFI_SUCCESS; goto Done; - } else if ((Variable.CurrPtr->State == VAR_ADDED) || - (Variable.CurrPtr->State == (VAR_ADDED & VAR_IN_DELETED_TRANSITION))) { + } else if ((Variable->CurrPtr->State == VAR_ADDED) || + (Variable->CurrPtr->State == (VAR_ADDED & VAR_IN_DELETED_TRANSITION))) { // // Mark the old variable as in delete transition // - State = Variable.CurrPtr->State; + State = Variable->CurrPtr->State; State &= VAR_IN_DELETED_TRANSITION; Status = UpdateVariableStore ( &mVariableModuleGlobal->VariableGlobal, - Variable.Volatile, + Variable->Volatile, FALSE, Fvb, - (UINTN) &Variable.CurrPtr->State, + (UINTN) &Variable->CurrPtr->State, sizeof (UINT8), &State ); @@ -1383,9 +1443,9 @@ RuntimeServiceSetVariable ( goto Done; } } - } else if (Status == EFI_NOT_FOUND) { + } else { // - // Create a new variable + // Not found existing variable. Create a new variable // // @@ -1405,12 +1465,6 @@ RuntimeServiceSetVariable ( Status = EFI_INVALID_PARAMETER; goto Done; } - } else { - // - // Status should be EFI_INVALID_PARAMETER here according to return status of FindVariable(). - // - ASSERT (Status == EFI_INVALID_PARAMETER); - goto Done; } // @@ -1475,7 +1529,8 @@ RuntimeServiceSetVariable ( // // Perform garbage collection & reclaim operation // - Status = Reclaim (mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase, NonVolatileOffset, FALSE, Variable.CurrPtr); + Status = Reclaim (mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase, + &mVariableModuleGlobal->NonVolatileLastVariableOffset, FALSE, Variable->CurrPtr); if (EFI_ERROR (Status)) { goto Done; } @@ -1489,7 +1544,6 @@ RuntimeServiceSetVariable ( Status = EFI_OUT_OF_RESOURCES; goto Done; } - Reclaimed = TRUE; } // @@ -1507,7 +1561,7 @@ RuntimeServiceSetVariable ( FALSE, TRUE, Fvb, - *NonVolatileOffset, + mVariableModuleGlobal->NonVolatileLastVariableOffset, sizeof (VARIABLE_HEADER), (UINT8 *) NextVariable ); @@ -1525,7 +1579,7 @@ RuntimeServiceSetVariable ( FALSE, TRUE, Fvb, - *NonVolatileOffset, + mVariableModuleGlobal->NonVolatileLastVariableOffset, sizeof (VARIABLE_HEADER), (UINT8 *) NextVariable ); @@ -1541,7 +1595,7 @@ RuntimeServiceSetVariable ( FALSE, TRUE, Fvb, - *NonVolatileOffset + sizeof (VARIABLE_HEADER), + mVariableModuleGlobal->NonVolatileLastVariableOffset + sizeof (VARIABLE_HEADER), (UINT32) VarSize - sizeof (VARIABLE_HEADER), (UINT8 *) NextVariable + sizeof (VARIABLE_HEADER) ); @@ -1558,7 +1612,7 @@ RuntimeServiceSetVariable ( FALSE, TRUE, Fvb, - *NonVolatileOffset, + mVariableModuleGlobal->NonVolatileLastVariableOffset, sizeof (VARIABLE_HEADER), (UINT8 *) NextVariable ); @@ -1567,7 +1621,7 @@ RuntimeServiceSetVariable ( goto Done; } - *NonVolatileOffset = HEADER_ALIGN (*NonVolatileOffset + VarSize); + mVariableModuleGlobal->NonVolatileLastVariableOffset += HEADER_ALIGN (VarSize); if ((Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) != 0) { mVariableModuleGlobal->HwErrVariableTotalSize += HEADER_ALIGN (VarSize); @@ -1580,25 +1634,25 @@ RuntimeServiceSetVariable ( // Volatile = TRUE; - if ((UINT32) (VarSize +*VolatileOffset) > + if ((UINT32) (VarSize + mVariableModuleGlobal->VolatileLastVariableOffset) > ((VARIABLE_STORE_HEADER *) ((UINTN) (mVariableModuleGlobal->VariableGlobal.VolatileVariableBase)))->Size) { // // Perform garbage collection & reclaim operation // - Status = Reclaim (mVariableModuleGlobal->VariableGlobal.VolatileVariableBase, VolatileOffset, TRUE, Variable.CurrPtr); + Status = Reclaim (mVariableModuleGlobal->VariableGlobal.VolatileVariableBase, + &mVariableModuleGlobal->VolatileLastVariableOffset, TRUE, Variable->CurrPtr); if (EFI_ERROR (Status)) { goto Done; } // // If still no enough space, return out of resources // - if ((UINT32) (VarSize +*VolatileOffset) > + if ((UINT32) (VarSize + mVariableModuleGlobal->VolatileLastVariableOffset) > ((VARIABLE_STORE_HEADER *) ((UINTN) (mVariableModuleGlobal->VariableGlobal.VolatileVariableBase)))->Size ) { Status = EFI_OUT_OF_RESOURCES; goto Done; } - Reclaimed = TRUE; } @@ -1608,7 +1662,7 @@ RuntimeServiceSetVariable ( TRUE, TRUE, Fvb, - *VolatileOffset, + mVariableModuleGlobal->VolatileLastVariableOffset, (UINT32) VarSize, (UINT8 *) NextVariable ); @@ -1617,37 +1671,328 @@ RuntimeServiceSetVariable ( goto Done; } - *VolatileOffset = HEADER_ALIGN (*VolatileOffset + VarSize); + mVariableModuleGlobal->VolatileLastVariableOffset += HEADER_ALIGN (VarSize); } + // // Mark the old variable as deleted // - if (!Reclaimed && !EFI_ERROR (Status) && Variable.CurrPtr != NULL) { - State = Variable.CurrPtr->State; + if (!Reclaimed && !EFI_ERROR (Status) && Variable->CurrPtr != NULL) { + State = Variable->CurrPtr->State; State &= VAR_DELETED; Status = UpdateVariableStore ( - &mVariableModuleGlobal->VariableGlobal, - Variable.Volatile, - FALSE, - Fvb, - (UINTN) &Variable.CurrPtr->State, - sizeof (UINT8), - &State - ); - - if (!EFI_ERROR (Status)) { - UpdateVariableInfo (VariableName, VendorGuid, Volatile, FALSE, TRUE, FALSE, FALSE); - UpdateVariableCache (VariableName, VendorGuid, Attributes, DataSize, Data); + &mVariableModuleGlobal->VariableGlobal, + Variable->Volatile, + FALSE, + Fvb, + (UINTN) &Variable->CurrPtr->State, + sizeof (UINT8), + &State + ); + } + + if (!EFI_ERROR (Status)) { + UpdateVariableInfo (VariableName, VendorGuid, Volatile, FALSE, TRUE, FALSE, FALSE); + UpdateVariableCache (VariableName, VendorGuid, Attributes, DataSize, Data); + } + +Done: + return Status; +} + +/** + + This code finds variable in storage blocks (Volatile or Non-Volatile). + + @param VariableName Name of Variable to be found. + @param VendorGuid Variable vendor GUID. + @param Attributes Attribute value of the variable found. + @param DataSize Size of Data found. If size is less than the + data, this value contains the required size. + @param Data Data pointer. + + @return EFI_INVALID_PARAMETER Invalid parameter + @return EFI_SUCCESS Find the specified variable + @return EFI_NOT_FOUND Not found + @return EFI_BUFFER_TO_SMALL DataSize is too small for the result + +**/ +EFI_STATUS +EFIAPI +RuntimeServiceGetVariable ( + IN CHAR16 *VariableName, + IN EFI_GUID *VendorGuid, + OUT UINT32 *Attributes OPTIONAL, + IN OUT UINTN *DataSize, + OUT VOID *Data + ) +{ + EFI_STATUS Status; + VARIABLE_POINTER_TRACK Variable; + UINTN VarDataSize; + + if (VariableName == NULL || VendorGuid == NULL || DataSize == NULL) { + return EFI_INVALID_PARAMETER; + } + + AcquireLockOnlyAtBootTime(&mVariableModuleGlobal->VariableGlobal.VariableServicesLock); + + // + // Find existing variable + // + Status = FindVariableInCache (VariableName, VendorGuid, Attributes, DataSize, Data); + if ((Status == EFI_BUFFER_TOO_SMALL) || (Status == EFI_SUCCESS)){ + // Hit in the Cache + UpdateVariableInfo (VariableName, VendorGuid, FALSE, TRUE, FALSE, FALSE, TRUE); + goto Done; + } + + Status = FindVariable (VariableName, VendorGuid, &Variable, &mVariableModuleGlobal->VariableGlobal); + if (Variable.CurrPtr == NULL || EFI_ERROR (Status)) { + goto Done; + } + + // + // Get data size + // + VarDataSize = DataSizeOfVariable (Variable.CurrPtr); + ASSERT (VarDataSize != 0); + + if (*DataSize >= VarDataSize) { + if (Data == NULL) { + Status = EFI_INVALID_PARAMETER; + goto Done; } - goto Done; + + CopyMem (Data, GetVariableDataPtr (Variable.CurrPtr), VarDataSize); + if (Attributes != NULL) { + *Attributes = Variable.CurrPtr->Attributes; + } + + *DataSize = VarDataSize; + UpdateVariableInfo (VariableName, VendorGuid, Variable.Volatile, TRUE, FALSE, FALSE, FALSE); + UpdateVariableCache (VariableName, VendorGuid, Variable.CurrPtr->Attributes, VarDataSize, Data); + + Status = EFI_SUCCESS; + goto Done; + } else { + *DataSize = VarDataSize; + Status = EFI_BUFFER_TOO_SMALL; + goto Done; } - Status = EFI_SUCCESS; - UpdateVariableInfo (VariableName, VendorGuid, Volatile, FALSE, TRUE, FALSE, FALSE); - UpdateVariableCache (VariableName, VendorGuid, Attributes, DataSize, Data); +Done: + ReleaseLockOnlyAtBootTime (&mVariableModuleGlobal->VariableGlobal.VariableServicesLock); + return Status; +} + + + +/** + + This code Finds the Next available variable. + + @param VariableNameSize Size of the variable name + @param VariableName Pointer to variable name + @param VendorGuid Variable Vendor Guid + + @return EFI_INVALID_PARAMETER Invalid parameter + @return EFI_SUCCESS Find the specified variable + @return EFI_NOT_FOUND Not found + @return EFI_BUFFER_TO_SMALL DataSize is too small for the result + +**/ +EFI_STATUS +EFIAPI +RuntimeServiceGetNextVariableName ( + IN OUT UINTN *VariableNameSize, + IN OUT CHAR16 *VariableName, + IN OUT EFI_GUID *VendorGuid + ) +{ + VARIABLE_POINTER_TRACK Variable; + UINTN VarNameSize; + EFI_STATUS Status; + + if (VariableNameSize == NULL || VariableName == NULL || VendorGuid == NULL) { + return EFI_INVALID_PARAMETER; + } + + AcquireLockOnlyAtBootTime(&mVariableModuleGlobal->VariableGlobal.VariableServicesLock); + + Status = FindVariable (VariableName, VendorGuid, &Variable, &mVariableModuleGlobal->VariableGlobal); + if (Variable.CurrPtr == NULL || EFI_ERROR (Status)) { + goto Done; + } + + if (VariableName[0] != 0) { + // + // If variable name is not NULL, get next variable + // + Variable.CurrPtr = GetNextVariablePtr (Variable.CurrPtr); + } + + while (TRUE) { + // + // If both volatile and non-volatile variable store are parsed, + // return not found + // + if (Variable.CurrPtr >= Variable.EndPtr || Variable.CurrPtr == NULL) { + Variable.Volatile = (BOOLEAN) (Variable.Volatile ^ ((BOOLEAN) 0x1)); + if (!Variable.Volatile) { + Variable.StartPtr = GetStartPointer ((VARIABLE_STORE_HEADER *) (UINTN) mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase); + Variable.EndPtr = GetEndPointer ((VARIABLE_STORE_HEADER *) ((UINTN) mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase)); + } else { + Status = EFI_NOT_FOUND; + goto Done; + } + + Variable.CurrPtr = Variable.StartPtr; + if (!IsValidVariableHeader (Variable.CurrPtr)) { + continue; + } + } + // + // Variable is found + // + if (IsValidVariableHeader (Variable.CurrPtr) && Variable.CurrPtr->State == VAR_ADDED) { + if ((EfiAtRuntime () && ((Variable.CurrPtr->Attributes & EFI_VARIABLE_RUNTIME_ACCESS) == 0)) == 0) { + VarNameSize = NameSizeOfVariable (Variable.CurrPtr); + ASSERT (VarNameSize != 0); + + if (VarNameSize <= *VariableNameSize) { + CopyMem ( + VariableName, + GetVariableNamePtr (Variable.CurrPtr), + VarNameSize + ); + CopyMem ( + VendorGuid, + &Variable.CurrPtr->VendorGuid, + sizeof (EFI_GUID) + ); + Status = EFI_SUCCESS; + } else { + Status = EFI_BUFFER_TOO_SMALL; + } + + *VariableNameSize = VarNameSize; + goto Done; + } + } + + Variable.CurrPtr = GetNextVariablePtr (Variable.CurrPtr); + } Done: + ReleaseLockOnlyAtBootTime (&mVariableModuleGlobal->VariableGlobal.VariableServicesLock); + return Status; +} + +/** + + This code sets variable in storage blocks (Volatile or Non-Volatile). + + @param VariableName Name of Variable to be found + @param VendorGuid Variable vendor GUID + @param Attributes Attribute value of the variable found + @param DataSize Size of Data found. If size is less than the + data, this value contains the required size. + @param Data Data pointer + + @return EFI_INVALID_PARAMETER Invalid parameter + @return EFI_SUCCESS Set successfully + @return EFI_OUT_OF_RESOURCES Resource not enough to set variable + @return EFI_NOT_FOUND Not found + @return EFI_WRITE_PROTECTED Variable is read-only + +**/ +EFI_STATUS +EFIAPI +RuntimeServiceSetVariable ( + IN CHAR16 *VariableName, + IN EFI_GUID *VendorGuid, + IN UINT32 Attributes, + IN UINTN DataSize, + IN VOID *Data + ) +{ + VARIABLE_POINTER_TRACK Variable; + EFI_STATUS Status; + VARIABLE_HEADER *NextVariable; + EFI_PHYSICAL_ADDRESS Point; + + // + // Check input parameters + // + if (VariableName == NULL || VariableName[0] == 0 || VendorGuid == NULL) { + return EFI_INVALID_PARAMETER; + } + // + // Make sure if runtime bit is set, boot service bit is set also + // + if ((Attributes & (EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS)) == EFI_VARIABLE_RUNTIME_ACCESS) { + return EFI_INVALID_PARAMETER; + } + + // + // The size of the VariableName, including the Unicode Null in bytes plus + // the DataSize is limited to maximum size of FixedPcdGet32(PcdMaxHardwareErrorVariableSize) + // bytes for HwErrRec, and FixedPcdGet32(PcdMaxVariableSize) bytes for the others. + // + if ((Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == EFI_VARIABLE_HARDWARE_ERROR_RECORD) { + if ((DataSize > FixedPcdGet32(PcdMaxHardwareErrorVariableSize)) || + (sizeof (VARIABLE_HEADER) + StrSize (VariableName) + DataSize > FixedPcdGet32(PcdMaxHardwareErrorVariableSize))) { + return EFI_INVALID_PARAMETER; + } + // + // According to UEFI spec, HARDWARE_ERROR_RECORD variable name convention should be L"HwErrRecXXXX" + // + if (StrnCmp(VariableName, L"HwErrRec", StrLen(L"HwErrRec")) != 0) { + return EFI_INVALID_PARAMETER; + } + } else { + // + // The size of the VariableName, including the Unicode Null in bytes plus + // the DataSize is limited to maximum size of FixedPcdGet32(PcdMaxVariableSize) bytes. + // + if ((DataSize > FixedPcdGet32(PcdMaxVariableSize)) || + (sizeof (VARIABLE_HEADER) + StrSize (VariableName) + DataSize > FixedPcdGet32(PcdMaxVariableSize))) { + return EFI_INVALID_PARAMETER; + } + } + + AcquireLockOnlyAtBootTime(&mVariableModuleGlobal->VariableGlobal.VariableServicesLock); + + // + // Consider reentrant in MCA/INIT/NMI. It needs be reupdated; + // + if (1 < InterlockedIncrement (&mVariableModuleGlobal->VariableGlobal.ReentrantState)) { + Point = mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase;; + // + // Parse non-volatile variable data and get last variable offset + // + NextVariable = GetStartPointer ((VARIABLE_STORE_HEADER *) (UINTN) Point); + while ((NextVariable < GetEndPointer ((VARIABLE_STORE_HEADER *) (UINTN) Point)) + && IsValidVariableHeader (NextVariable)) { + NextVariable = GetNextVariablePtr (NextVariable); + } + mVariableModuleGlobal->NonVolatileLastVariableOffset = (UINTN) NextVariable - (UINTN) Point; + } + + // + // Check whether the input variable is already existed + // + FindVariable (VariableName, VendorGuid, &Variable, &mVariableModuleGlobal->VariableGlobal); + + // + // Hook the operation of setting PlatformLangCodes/PlatformLang and LangCodes/Lang + // + AutoUpdateLangVariable (VariableName, Data, DataSize); + + Status = UpdateVariable (VariableName, VendorGuid, Data, DataSize, Attributes, &Variable); + InterlockedDecrement (&mVariableModuleGlobal->VariableGlobal.ReentrantState); ReleaseLockOnlyAtBootTime (&mVariableModuleGlobal->VariableGlobal.VariableServicesLock); @@ -1894,15 +2239,12 @@ VariableCommonInitialize ( // // Allocate runtime memory for variable driver global structure. // - mVariableModuleGlobal = AllocateRuntimePool (sizeof (VARIABLE_MODULE_GLOBAL)); + mVariableModuleGlobal = AllocateRuntimeZeroPool (sizeof (VARIABLE_MODULE_GLOBAL)); if (mVariableModuleGlobal == NULL) { return EFI_OUT_OF_RESOURCES; } EfiInitializeLock(&mVariableModuleGlobal->VariableGlobal.VariableServicesLock, TPL_NOTIFY); - mVariableModuleGlobal->VariableGlobal.ReentrantState = 0; - mVariableModuleGlobal->CommonVariableTotalSize = 0; - mVariableModuleGlobal->HwErrVariableTotalSize = 0; // // Allocate memory for volatile variable store, note that there is a scratch space to store scratch data. diff --git a/MdeModulePkg/Universal/Variable/RuntimeDxe/Variable.h b/MdeModulePkg/Universal/Variable/RuntimeDxe/Variable.h index 85e7f70ed5..9c3b43f715 100644 --- a/MdeModulePkg/Universal/Variable/RuntimeDxe/Variable.h +++ b/MdeModulePkg/Universal/Variable/RuntimeDxe/Variable.h @@ -59,6 +59,10 @@ typedef struct { UINTN NonVolatileLastVariableOffset; UINTN CommonVariableTotalSize; UINTN HwErrVariableTotalSize; + CHAR8 PlatformLangCodes[256]; //Pre-allocate 256 bytes space to accommodate the PlatformlangCodes. + CHAR8 LangCodes[256]; //Pre-allocate 256 bytes space to accommodate the langCodes. + CHAR8 PlatformLang[8]; //Pre-allocate 8 bytes space to accommodate the Platformlang variable. + CHAR8 Lang[4]; //Pre-allocate 4 bytes space to accommodate the lang variable. EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *FvbInstance; } VARIABLE_MODULE_GLOBAL; diff --git a/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableRuntimeDxe.inf b/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableRuntimeDxe.inf index 64246a707f..e0d60dd30a 100644 --- a/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableRuntimeDxe.inf +++ b/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableRuntimeDxe.inf @@ -77,6 +77,9 @@ [Depex] gEfiFirmwareVolumeBlockProtocolGuid AND gEfiFaultTolerantWriteProtocolGuid +[BuildOptions.common] + MSFT:*_*_*_CC_FLAGS = /nologo /W4 /WX /Gy /c /D UNICODE /GL- /FI$(DEST_DIR_DEBUG)/AutoGen.h /EHs-c- /GF /Gs8192 /Zi /Gm + # [Event] # ## # # Event will be signaled for VIRTUAL_ADDRESS_CHANGE event. -- cgit v1.2.3