X-Git-Url: https://git.proxmox.com/?a=blobdiff_plain;f=DuetPkg%2FFSVariable%2FFSVariable.c;h=9a50cca72bc5f5440f5d4b204ec3a60542f797bf;hb=439b0e239bb9a7c924b6ddca10f82b68f68da1e8;hp=041369106776f3bf7acaca6b9e00aaca491777c1;hpb=9071550e8697ed9df3d24b369bd30e3f0e190d1f;p=mirror_edk2.git diff --git a/DuetPkg/FSVariable/FSVariable.c b/DuetPkg/FSVariable/FSVariable.c index 0413691067..9a50cca72b 100644 --- a/DuetPkg/FSVariable/FSVariable.c +++ b/DuetPkg/FSVariable/FSVariable.c @@ -1,7 +1,7 @@ /*++ -Copyright (c) 2006 - 2007, Intel Corporation -All rights reserved. This program and the accompanying materials +Copyright (c) 2006 - 2010, Intel Corporation. All rights reserved.
+This program and the accompanying materials are licensed and made available under the terms and conditions of the BSD License which accompanies this distribution. The full text of the license may be found at http://opensource.org/licenses/bsd-license.php @@ -35,15 +35,45 @@ VARIABLE_STORE_HEADER mStoreHeaderTemplate = { // VARIABLE_GLOBAL *mGlobal; -STATIC +/** + 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 + ); + VOID EFIAPI -OnVirtualAddressChange ( +OnVirtualAddressChangeFsv ( IN EFI_EVENT Event, IN VOID *Context ); -STATIC VOID EFIAPI OnSimpleFileSystemInstall ( @@ -51,7 +81,6 @@ OnSimpleFileSystemInstall ( IN VOID *Context ); -STATIC BOOLEAN IsValidVariableHeader ( IN VARIABLE_HEADER *Variable @@ -71,17 +100,13 @@ Returns: --*/ { - if (Variable == NULL || - Variable->StartId != VARIABLE_DATA || - (sizeof (VARIABLE_HEADER) + Variable->NameSize + Variable->DataSize) > MAX_VARIABLE_SIZE - ) { + if (Variable == NULL || Variable->StartId != VARIABLE_DATA) { return FALSE; } return TRUE; } -STATIC VARIABLE_STORE_STATUS GetVariableStoreStatus ( IN VARIABLE_STORE_HEADER *VarStoreHeader @@ -104,15 +129,18 @@ Returns: --*/ { - if ((VarStoreHeader->Signature == mStoreHeaderTemplate.Signature) && + if (CompareGuid (&VarStoreHeader->Signature, &mStoreHeaderTemplate.Signature) && (VarStoreHeader->Format == mStoreHeaderTemplate.Format) && (VarStoreHeader->State == mStoreHeaderTemplate.State) ) { return EfiValid; - } else if (VarStoreHeader->Signature == VAR_DEFAULT_VALUE_32 && - VarStoreHeader->Size == VAR_DEFAULT_VALUE_32 && - VarStoreHeader->Format == VAR_DEFAULT_VALUE && - VarStoreHeader->State == VAR_DEFAULT_VALUE + } else if (((UINT32 *)(&VarStoreHeader->Signature))[0] == VAR_DEFAULT_VALUE_32 && + ((UINT32 *)(&VarStoreHeader->Signature))[1] == VAR_DEFAULT_VALUE_32 && + ((UINT32 *)(&VarStoreHeader->Signature))[2] == VAR_DEFAULT_VALUE_32 && + ((UINT32 *)(&VarStoreHeader->Signature))[3] == VAR_DEFAULT_VALUE_32 && + VarStoreHeader->Size == VAR_DEFAULT_VALUE_32 && + VarStoreHeader->Format == VAR_DEFAULT_VALUE && + VarStoreHeader->State == VAR_DEFAULT_VALUE ) { return EfiRaw; @@ -121,7 +149,6 @@ Returns: } } -STATIC UINT8 * GetVariableDataPtr ( IN VARIABLE_HEADER *Variable @@ -148,7 +175,6 @@ Returns: return (UINT8 *) ((UINTN) GET_VARIABLE_NAME_PTR (Variable) + Variable->NameSize + GET_PAD_SIZE (Variable->NameSize)); } -STATIC VARIABLE_HEADER * GetNextVariablePtr ( IN VARIABLE_HEADER *Variable @@ -178,7 +204,6 @@ Returns: return (VARIABLE_HEADER *) ((UINTN) GetVariableDataPtr (Variable) + Variable->DataSize + GET_PAD_SIZE (Variable->DataSize)); } -STATIC VARIABLE_HEADER * GetEndPointer ( IN VARIABLE_STORE_HEADER *VarStoreHeader @@ -250,7 +275,6 @@ Returns: return FALSE; } -STATIC EFI_STATUS Reclaim ( IN VARIABLE_STORAGE_TYPE StorageType, @@ -291,7 +315,13 @@ Returns: // Variable = (VARIABLE_HEADER *) (VariableStoreHeader + 1); - + // + // recaluate the total size of Common/HwErr type variables in non-volatile area. + // + if (!StorageType) { + mGlobal->CommonVariableTotalSize = 0; + mGlobal->HwErrVariableTotalSize = 0; + } // // To make the reclaim, here we just allocate a memory that equal to the original memory // @@ -300,7 +330,7 @@ Returns: Status = gBS->AllocatePool ( EfiBootServicesData, ValidBufferSize, - &ValidBuffer + (VOID**) &ValidBuffer ); if (EFI_ERROR (Status)) { return Status; @@ -332,6 +362,11 @@ Returns: CopyMem (CurrPtr, (UINT8 *) Variable, VariableSize); ValidBufferSize += VariableSize; CurrPtr += VariableSize; + if ((!StorageType) && ((Variable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == EFI_VARIABLE_HARDWARE_ERROR_RECORD)) { + mGlobal->HwErrVariableTotalSize += VariableSize; + } else if ((!StorageType) && ((Variable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) != EFI_VARIABLE_HARDWARE_ERROR_RECORD)) { + mGlobal->CommonVariableTotalSize += VariableSize; + } } else if (Variable->State == (VAR_ADDED & VAR_IN_DELETED_TRANSITION)) { // // As variables that with the same guid and name may exist in NV due to power failure during SetVariable, @@ -348,11 +383,18 @@ Returns: } CurrPtr += VariableSize; ValidBufferSize += VariableSize; + if ((!StorageType) && ((Variable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == EFI_VARIABLE_HARDWARE_ERROR_RECORD)) { + mGlobal->HwErrVariableTotalSize += VariableSize; + } else if ((!StorageType) && ((Variable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) != EFI_VARIABLE_HARDWARE_ERROR_RECORD)) { + mGlobal->CommonVariableTotalSize += VariableSize; + } } } Variable = NextVariable; } + mGlobal->LastVariableOffset[StorageType] = ValidBufferSize; + // // TODO: cannot restore to original state, basic FTW needed // @@ -366,15 +408,18 @@ Returns: ValidBuffer ); - // ASSERT_EFI_ERROR (Status); + if (EFI_ERROR (Status)) { + // + // If error, then reset the last variable offset to zero. + // + mGlobal->LastVariableOffset[StorageType] = 0; + }; - mGlobal->LastVariableOffset[StorageType] = ValidBufferSize; gBS->FreePool (ValidBuffer); return Status; } -STATIC EFI_STATUS FindVariable ( IN CHAR16 *VariableName, @@ -438,7 +483,7 @@ Returns: PtrTrack->StartPtr = Variable; PtrTrack->EndPtr = GetEndPointer (VariableStoreHeader); - while (IsValidVariableHeader (Variable) && (Variable < PtrTrack->EndPtr)) { + while ((Variable < PtrTrack->EndPtr) && IsValidVariableHeader (Variable)) { if (Variable->State == VAR_ADDED) { if (!EfiAtRuntime () || (Variable->Attributes & EFI_VARIABLE_RUNTIME_ACCESS)) { if (VariableName[0] == 0) { @@ -504,279 +549,542 @@ Returns: return EFI_NOT_FOUND; } -EFI_STATUS -EFIAPI -GetVariable ( - IN CHAR16 *VariableName, - IN EFI_GUID *VendorGuid, - OUT UINT32 *Attributes OPTIONAL, - IN OUT UINTN *DataSize, - OUT VOID *Data - ) -/*++ - -Routine Description: +/** + 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 + RFC4646 and ISO639 language tags. + In ISO639 language tags, take 3-characters as a delimitation to find matched string and calculate the index. + In RFC4646 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 RFC4646. + + @retval the index of language in the language codes. + +**/ +UINTN +GetIndexFromSupportedLangCodes( + IN CHAR8 *SupportedLang, + IN CHAR8 *Lang, + IN BOOLEAN Iso639Language + ) +{ + UINTN Index; + UINTN CompareLength; + UINTN LanguageLength; + + if (Iso639Language) { + CompareLength = ISO_639_2_ENTRY_SIZE; + 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 RFC4646 language code + // + Index = 0; + for (LanguageLength = 0; Lang[LanguageLength] != '\0'; LanguageLength++); - This code finds variable in storage blocks (Volatile or Non-Volatile) + for (Index = 0; *SupportedLang != '\0'; Index++, SupportedLang += CompareLength) { + // + // Skip ';' characters in SupportedLang + // + for (; *SupportedLang != '\0' && *SupportedLang == ';'; SupportedLang++); + // + // Determine the length of the next language code in SupportedLang + // + for (CompareLength = 0; SupportedLang[CompareLength] != '\0' && SupportedLang[CompareLength] != ';'; CompareLength++); + + if ((CompareLength == LanguageLength) && + (AsciiStrnCmp (Lang, SupportedLang, CompareLength) == 0)) { + // + // Successfully find the index of Lang string in SupportedLang string. + // + return Index; + } + } + ASSERT (FALSE); + return 0; + } +} -Arguments: +/** + 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 + RFC4646 and ISO639 language tags. + In ISO639 language tags, take 3-characters as a delimitation. Find language string according to the index. + In RFC4646 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 RFC4646. + + @retval the language string in the language codes. + +**/ +CHAR8 * +GetLangFromSupportedLangCodes ( + IN CHAR8 *SupportedLang, + IN UINTN Index, + IN BOOLEAN Iso639Language +) +{ + UINTN SubIndex; + UINTN CompareLength; + CHAR8 *Supported; - VariableName Name of Variable to be found - VendorGuid Variable vendor GUID - Attributes OPTIONAL Attribute value of the variable found - DataSize Size of Data found. If size is less than the - data, this value contains the required size. - Data Data pointer + 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 = ISO_639_2_ENTRY_SIZE; + mGlobal->Lang[CompareLength] = '\0'; + return CopyMem (mGlobal->Lang, SupportedLang + Index * CompareLength, CompareLength); -Returns: + } 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. + // + mGlobal->PlatformLang[CompareLength] = '\0'; + return CopyMem (mGlobal->PlatformLang, Supported - CompareLength, CompareLength); + } + SubIndex++; - EFI STATUS + // + // Skip ';' characters in Supported + // + for (; *Supported != '\0' && *Supported == ';'; Supported++); + } + } +} ---*/ +/** + Returns a pointer to an allocated buffer that contains the best matching language + from a set of supported languages. + + This function supports both ISO 639-2 and RFC 4646 language codes, but language + code types may not be mixed in a single call to this function. This function + supports a variable argument list that allows the caller to pass in a prioritized + list of language codes to test against all the language codes in SupportedLanguages. + + If SupportedLanguages is NULL, then ASSERT(). + + @param[in] SupportedLanguages A pointer to a Null-terminated ASCII string that + contains a set of language codes in the format + specified by Iso639Language. + @param[in] Iso639Language If TRUE, then all language codes are assumed to be + in ISO 639-2 format. If FALSE, then all language + codes are assumed to be in RFC 4646 language format + @param[in] ... A variable argument list that contains pointers to + Null-terminated ASCII strings that contain one or more + language codes in the format specified by Iso639Language. + The first language code from each of these language + code lists is used to determine if it is an exact or + close match to any of the language codes in + SupportedLanguages. Close matches only apply to RFC 4646 + language codes, and the matching algorithm from RFC 4647 + is used to determine if a close match is present. If + an exact or close match is found, then the matching + language code from SupportedLanguages is returned. If + no matches are found, then the next variable argument + parameter is evaluated. The variable argument list + is terminated by a NULL. + + @retval NULL The best matching language could not be found in SupportedLanguages. + @retval NULL There are not enough resources available to return the best matching + language. + @retval Other A pointer to a Null-terminated ASCII string that is the best matching + language in SupportedLanguages. + +**/ +CHAR8 * +EFIAPI +VariableGetBestLanguage ( + IN CONST CHAR8 *SupportedLanguages, + IN BOOLEAN Iso639Language, + ... + ) { - VARIABLE_POINTER_TRACK Variable; - UINTN VarDataSize; - EFI_STATUS Status; + VA_LIST Args; + CHAR8 *Language; + UINTN CompareLength; + UINTN LanguageLength; + CONST CHAR8 *Supported; + CHAR8 *Buffer; - if (VariableName == NULL || VendorGuid == NULL || DataSize == NULL) { - return EFI_INVALID_PARAMETER; - } + ASSERT (SupportedLanguages != NULL); - // - // Find existing variable - // - Status = FindVariable (VariableName, VendorGuid, &Variable); + VA_START (Args, Iso639Language); + while ((Language = VA_ARG (Args, CHAR8 *)) != NULL) { + // + // Default to ISO 639-2 mode + // + CompareLength = 3; + LanguageLength = MIN (3, AsciiStrLen (Language)); - if (Variable.CurrPtr == NULL || EFI_ERROR (Status)) { - return Status; - } - // - // Get data size - // - VarDataSize = Variable.CurrPtr->DataSize; - if (*DataSize >= VarDataSize) { - if (Data == NULL) { - return EFI_INVALID_PARAMETER; + // + // If in RFC 4646 mode, then determine the length of the first RFC 4646 language code in Language + // + if (!Iso639Language) { + for (LanguageLength = 0; Language[LanguageLength] != 0 && Language[LanguageLength] != ';'; LanguageLength++); } - CopyMem (Data, GetVariableDataPtr (Variable.CurrPtr), VarDataSize); - if (Attributes != NULL) { - *Attributes = Variable.CurrPtr->Attributes; - } + // + // Trim back the length of Language used until it is empty + // + while (LanguageLength > 0) { + // + // Loop through all language codes in SupportedLanguages + // + for (Supported = SupportedLanguages; *Supported != '\0'; Supported += CompareLength) { + // + // In RFC 4646 mode, then Loop through all language codes in SupportedLanguages + // + if (!Iso639Language) { + // + // Skip ';' characters in Supported + // + for (; *Supported != '\0' && *Supported == ';'; Supported++); + // + // Determine the length of the next language code in Supported + // + for (CompareLength = 0; Supported[CompareLength] != 0 && Supported[CompareLength] != ';'; CompareLength++); + // + // If Language is longer than the Supported, then skip to the next language + // + if (LanguageLength > CompareLength) { + continue; + } + } + // + // See if the first LanguageLength characters in Supported match Language + // + if (AsciiStrnCmp (Supported, Language, LanguageLength) == 0) { + VA_END (Args); - *DataSize = VarDataSize; + Buffer = Iso639Language ? mGlobal->Lang : mGlobal->PlatformLang; + Buffer[CompareLength] = '\0'; + return CopyMem (Buffer, Supported, CompareLength); + } + } - return EFI_SUCCESS; - } else { - *DataSize = VarDataSize; - return EFI_BUFFER_TOO_SMALL; + if (Iso639Language) { + // + // If ISO 639 mode, then each language can only be tested once + // + LanguageLength = 0; + } else { + // + // If RFC 4646 mode, then trim Language from the right to the next '-' character + // + for (LanguageLength--; LanguageLength > 0 && Language[LanguageLength] != '-'; LanguageLength--); + } + } } -} + VA_END (Args); -EFI_STATUS -EFIAPI -GetNextVariableName ( - IN OUT UINTN *VariableNameSize, - IN OUT CHAR16 *VariableName, - IN OUT EFI_GUID *VendorGuid - ) -/*++ + // + // No matches were found + // + return NULL; +} -Routine Description: +/** + Hook the operations in PlatformLangCodes, LangCodes, PlatformLang and Lang. - This code Finds the Next available variable + When setting Lang/LangCodes, simultaneously update PlatformLang/PlatformLangCodes. -Arguments: + 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. - VariableNameSize Size of the variable - VariableName Pointer to variable name - VendorGuid Variable Vendor Guid + @param[in] VariableName Name of variable -Returns: + @param[in] Data Variable data - EFI STATUS + @param[in] DataSize Size of data. 0 means delete ---*/ +**/ +VOID +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; + BOOLEAN SetLanguageCodes; - if (VariableNameSize == NULL || VariableName == NULL || VendorGuid == NULL) { - return EFI_INVALID_PARAMETER; + // + // Don't do updates for delete operation + // + if (DataSize == 0) { + return; } - Status = FindVariable (VariableName, VendorGuid, &Variable); + SetLanguageCodes = FALSE; - if (Variable.CurrPtr == NULL || EFI_ERROR (Status)) { - return Status; - } + if (StrCmp (VariableName, L"PlatformLangCodes") == 0) { + // + // PlatformLangCodes is a volatile variable, so it can not be updated at runtime. + // + if (EfiAtRuntime ()) { + return; + } + + SetLanguageCodes = TRUE; - if (VariableName[0] != 0) { // - // If variable name is not NULL, get next variable + // 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. // - Variable.CurrPtr = GetNextVariablePtr (Variable.CurrPtr); + if (mGlobal->PlatformLangCodes != NULL) { + FreePool (mGlobal->PlatformLangCodes); + } + mGlobal->PlatformLangCodes = AllocateRuntimeCopyPool (DataSize, Data); + ASSERT (mGlobal->PlatformLangCodes != NULL); + + // + // PlatformLang holds a single language from PlatformLangCodes, + // so the size of PlatformLangCodes is enough for the PlatformLang. + // + if (mGlobal->PlatformLang != NULL) { + FreePool (mGlobal->PlatformLang); + } + mGlobal->PlatformLang = AllocateRuntimePool (DataSize); + ASSERT (mGlobal->PlatformLang != NULL); + + } else if (StrCmp (VariableName, L"LangCodes") == 0) { + // + // LangCodes is a volatile variable, so it can not be updated at runtime. + // + if (EfiAtRuntime ()) { + return; + } + + SetLanguageCodes = TRUE; + + // + // 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. + // + if (mGlobal->LangCodes != NULL) { + FreePool (mGlobal->LangCodes); + } + mGlobal->LangCodes = AllocateRuntimeCopyPool (DataSize, Data); + ASSERT (mGlobal->LangCodes != NULL); } - while (TRUE) { + if (SetLanguageCodes + && (mGlobal->PlatformLangCodes != NULL) + && (mGlobal->LangCodes != NULL)) { // - // The order we find variable is: 1). NonVolatile; 2). Volatile - // If both volatile and non-volatile variable store are parsed, - // return not found + // Update Lang if PlatformLang is already set + // Update PlatformLang if Lang is already set // - if (Variable.CurrPtr >= Variable.EndPtr || Variable.CurrPtr == NULL) { - if (Variable.Type == Volatile) { + Status = FindVariable (L"PlatformLang", &gEfiGlobalVariableGuid, &Variable); + if (!EFI_ERROR (Status)) { + // + // Update Lang + // + VariableName = L"PlatformLang"; + Data = GetVariableDataPtr (Variable.CurrPtr); + DataSize = Variable.CurrPtr->DataSize; + } else { + Status = FindVariable (L"Lang", &gEfiGlobalVariableGuid, &Variable); + if (!EFI_ERROR (Status)) { // - // Since we met the end of Volatile storage, we have parsed all the stores. + // Update PlatformLang // - return EFI_NOT_FOUND; + VariableName = L"Lang"; + Data = GetVariableDataPtr (Variable.CurrPtr); + DataSize = Variable.CurrPtr->DataSize; + } else { + // + // Neither PlatformLang nor Lang is set, directly return + // + return; } + } + } + + // + // 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"PlatformLang") == 0) { + // + // Update Lang when PlatformLangCodes/LangCodes were set. + // + if ((mGlobal->PlatformLangCodes != NULL) && (mGlobal->LangCodes != NULL)) { // - // End of NonVolatile, continue to parse Volatile + // When setting PlatformLang, firstly get most matched language string from supported language codes. // - Variable.Type = Volatile; - Variable.StartPtr = (VARIABLE_HEADER *) ((VARIABLE_STORE_HEADER *) mGlobal->VariableBase[Volatile] + 1); - Variable.EndPtr = (VARIABLE_HEADER *) GetEndPointer ((VARIABLE_STORE_HEADER *) mGlobal->VariableBase[Volatile]); + BestPlatformLang = VariableGetBestLanguage (mGlobal->PlatformLangCodes, FALSE, Data, NULL); + if (BestPlatformLang != NULL) { + // + // Get the corresponding index in language codes. + // + Index = GetIndexFromSupportedLangCodes (mGlobal->PlatformLangCodes, BestPlatformLang, FALSE); - Variable.CurrPtr = Variable.StartPtr; - if (!IsValidVariableHeader (Variable.CurrPtr)) { - continue; + // + // Get the corresponding ISO639 language tag according to RFC4646 language tag. + // + BestLang = GetLangFromSupportedLangCodes (mGlobal->LangCodes, Index, TRUE); + + // + // Successfully convert PlatformLang to Lang, and set the BestLang value into Lang variable simultaneously. + // + FindVariable(L"Lang", &gEfiGlobalVariableGuid, &Variable); + + 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) { // - // Variable is found + // Update PlatformLang when PlatformLangCodes/LangCodes were set. // - if (IsValidVariableHeader (Variable.CurrPtr) && - ((Variable.CurrPtr->State == VAR_ADDED) || - (Variable.CurrPtr->State == (VAR_ADDED & VAR_IN_DELETED_TRANSITION)))) { - if (!EfiAtRuntime () || (Variable.CurrPtr->Attributes & EFI_VARIABLE_RUNTIME_ACCESS)) { - VarNameSize = Variable.CurrPtr->NameSize; - if (VarNameSize <= *VariableNameSize) { - CopyMem ( - VariableName, - GET_VARIABLE_NAME_PTR (Variable.CurrPtr), - VarNameSize - ); - CopyMem ( - VendorGuid, - &Variable.CurrPtr->VendorGuid, - sizeof (EFI_GUID) - ); - Status = EFI_SUCCESS; - } else { - Status = EFI_BUFFER_TOO_SMALL; - } - - *VariableNameSize = VarNameSize; - return Status; + if ((mGlobal->PlatformLangCodes != NULL) && (mGlobal->LangCodes != NULL)) { + // + // When setting Lang, firstly get most matched language string from supported language codes. + // + BestLang = VariableGetBestLanguage (mGlobal->LangCodes, TRUE, Data, NULL); + if (BestLang != NULL) { + // + // Get the corresponding index in language codes. + // + Index = GetIndexFromSupportedLangCodes (mGlobal->LangCodes, BestLang, TRUE); + + // + // Get the corresponding RFC4646 language tag according to ISO639 language tag. + // + BestPlatformLang = GetLangFromSupportedLangCodes (mGlobal->PlatformLangCodes, Index, FALSE); + + // + // Successfully convert Lang to PlatformLang, and set the BestPlatformLang value into PlatformLang variable simultaneously. + // + FindVariable(L"PlatformLang", &gEfiGlobalVariableGuid, &Variable); + + Status = UpdateVariable (L"PlatformLang", &gEfiGlobalVariableGuid, BestPlatformLang, + AsciiStrSize (BestPlatformLang), Attributes, &Variable); + + DEBUG ((EFI_D_INFO, "Variable Driver Auto Update Lang, Lang:%a, PlatformLang:%a\n", BestLang, BestPlatformLang)); + ASSERT_EFI_ERROR (Status); } } - - Variable.CurrPtr = GetNextVariablePtr (Variable.CurrPtr); } - - return EFI_NOT_FOUND; } -EFI_STATUS -EFIAPI -SetVariable ( - IN CHAR16 *VariableName, - IN EFI_GUID *VendorGuid, - IN UINT32 Attributes, - IN UINTN DataSize, - IN VOID *Data - ) -/*++ +/** + Update the variable region with Variable information. These are the same + arguments as the EFI Variable services. -Routine Description: + @param[in] VariableName Name of variable - This code sets variable in storage blocks (Volatile or Non-Volatile) + @param[in] VendorGuid Guid of variable -Arguments: + @param[in] Data Variable data - VariableName Name of Variable to be found - VendorGuid Variable vendor GUID - Attributes Attribute value of the variable found - DataSize Size of Data found. If size is less than the - data, this value contains the required size. - Data Data pointer + @param[in] DataSize Size of data. 0 means delete -Returns: - - EFI_INVALID_PARAMETER - Invalid parameter - EFI_SUCCESS - Set successfully - EFI_OUT_OF_RESOURCES - Resource not enough to set variable - EFI_NOT_FOUND - Not found - EFI_DEVICE_ERROR - Variable can not be saved due to hardware failure - EFI_WRITE_PROTECTED - Variable is read-only + @param[in] Attributes Attribues of the variable ---*/ -{ - VARIABLE_POINTER_TRACK Variable; - EFI_STATUS Status; - VARIABLE_HEADER *NextVariable; - UINTN VarNameSize; - UINTN VarNameOffset; - UINTN VarDataOffset; - UINTN VarSize; - UINT8 State; - BOOLEAN Reclaimed; - VARIABLE_STORAGE_TYPE StorageType; - - Reclaimed = FALSE; - - // - // Check input parameters - // + @param[in] Variable The variable information which is used to keep track of variable usage. - 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; - } - -#if (EFI_SPECIFICATION_VERSION >= 0x0002000A) - // - // The size of the VariableName, including the Unicode Null in bytes plus - // the DataSize is limited to maximum size of MAX_HARDWARE_ERROR_VARIABLE_SIZE (32K) - // bytes for HwErrRec, and MAX_VARIABLE_SIZE (1024) bytes for the others. - // - if ((Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == EFI_VARIABLE_HARDWARE_ERROR_RECORD) { - if ((DataSize > MAX_HARDWARE_ERROR_VARIABLE_SIZE) || - (sizeof (VARIABLE_HEADER) + StrSize (VariableName) + DataSize > MAX_HARDWARE_ERROR_VARIABLE_SIZE)) { - return EFI_INVALID_PARAMETER; - } - } else { - if ((DataSize > MAX_VARIABLE_SIZE) || - (sizeof (VARIABLE_HEADER) + StrSize (VariableName) + DataSize > MAX_VARIABLE_SIZE)) { - 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 MAX_VARIABLE_SIZE (1024) bytes. - // - if ((DataSize > MAX_VARIABLE_SIZE) || - (sizeof (VARIABLE_HEADER) + StrSize (VariableName) + DataSize > MAX_VARIABLE_SIZE)) { - return EFI_INVALID_PARAMETER; - } -#endif - // - // Check whether the input variable is already existed - // + @retval EFI_SUCCESS The update operation is success. - Status = FindVariable (VariableName, VendorGuid, &Variable); + @retval EFI_OUT_OF_RESOURCES Variable region is full, can not write other data into this region. - if (Status == EFI_SUCCESS && Variable.CurrPtr != NULL) { +**/ +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 VarNameOffset; + UINTN VarDataOffset; + UINTN VarNameSize; + UINTN VarSize; + UINT8 State; + BOOLEAN Reclaimed; + VARIABLE_STORAGE_TYPE StorageType; + + Reclaimed = FALSE; + + if (Variable->CurrPtr != NULL) { // // Update/Delete existing variable // @@ -787,13 +1095,13 @@ Returns: // the volatile is ReadOnly, and SetVariable should be aborted and // return EFI_WRITE_PROTECTED. // - if (Variable.Type == Volatile) { + if (Variable->Type == Volatile) { return EFI_WRITE_PROTECTED; } // // Only variable have NV attribute can be updated/deleted in Runtime // - if (!(Variable.CurrPtr->Attributes & EFI_VARIABLE_NON_VOLATILE)) { + if (!(Variable->CurrPtr->Attributes & EFI_VARIABLE_NON_VOLATILE)) { return EFI_INVALID_PARAMETER; } } @@ -806,13 +1114,13 @@ Returns: // // Found this variable in storage // - State = Variable.CurrPtr->State; + State = Variable->CurrPtr->State; State &= VAR_DELETED; - Status = mGlobal->VariableStore[Variable.Type]->Write ( - mGlobal->VariableStore[Variable.Type], - VARIABLE_MEMBER_OFFSET (State, (UINTN) Variable.CurrPtr - (UINTN) Variable.StartPtr), - sizeof (Variable.CurrPtr->State), + Status = mGlobal->VariableStore[Variable->Type]->Write ( + mGlobal->VariableStore[Variable->Type], + VARIABLE_MEMBER_OFFSET (State, (UINTN) Variable->CurrPtr - (UINTN) Variable->StartPtr), + sizeof (Variable->CurrPtr->State), &State ); // @@ -827,22 +1135,22 @@ Returns: // 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) + if ((Variable->CurrPtr->DataSize == DataSize) && + (CompareMem (Data, GetVariableDataPtr (Variable->CurrPtr), DataSize) == 0) ) { return EFI_SUCCESS; - } 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 = mGlobal->VariableStore[Variable.Type]->Write ( - mGlobal->VariableStore[Variable.Type], - VARIABLE_MEMBER_OFFSET (State, (UINTN) Variable.CurrPtr - (UINTN) Variable.StartPtr), - sizeof (Variable.CurrPtr->State), + Status = mGlobal->VariableStore[Variable->Type]->Write ( + mGlobal->VariableStore[Variable->Type], + VARIABLE_MEMBER_OFFSET (State, (UINTN) Variable->CurrPtr - (UINTN) Variable->StartPtr), + sizeof (Variable->CurrPtr->State), &State ); // @@ -850,7 +1158,7 @@ Returns: // Discard file writing failure here. // } - } else if (Status == EFI_NOT_FOUND) { + } else { // // Create a new variable // @@ -870,11 +1178,6 @@ Returns: return EFI_INVALID_PARAMETER; } - } else { - // - // Status should be EFI_INVALID_PARAMETER here according to return status of FindVariable(). - // - return Status; } // @@ -930,7 +1233,7 @@ Returns: // // Perform garbage collection & reclaim operation // - Status = Reclaim (StorageType, Variable.CurrPtr); + Status = Reclaim (StorageType, Variable->CurrPtr); if (EFI_ERROR (Status)) { // // Reclaim error @@ -962,17 +1265,23 @@ Returns: // mGlobal->LastVariableOffset[StorageType] += VarSize; + if ((Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) != 0) { + mGlobal->HwErrVariableTotalSize += VarSize; + } else { + mGlobal->CommonVariableTotalSize += 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 = mGlobal->VariableStore[StorageType]->Write ( mGlobal->VariableStore[StorageType], - VARIABLE_MEMBER_OFFSET (State, (UINTN) Variable.CurrPtr - (UINTN) Variable.StartPtr), - sizeof (Variable.CurrPtr->State), + VARIABLE_MEMBER_OFFSET (State, (UINTN) Variable->CurrPtr - (UINTN) Variable->StartPtr), + sizeof (Variable->CurrPtr->State), &State ); // @@ -980,11 +1289,284 @@ Returns: // Discard file writing failure here. // } - return EFI_SUCCESS; } -#if (EFI_SPECIFICATION_VERSION >= 0x00020000) +EFI_STATUS +EFIAPI +DuetGetVariable ( + IN CHAR16 *VariableName, + IN EFI_GUID *VendorGuid, + OUT UINT32 *Attributes OPTIONAL, + IN OUT UINTN *DataSize, + OUT VOID *Data + ) +/*++ + +Routine Description: + + This code finds variable in storage blocks (Volatile or Non-Volatile) + +Arguments: + + VariableName Name of Variable to be found + VendorGuid Variable vendor GUID + Attributes OPTIONAL Attribute value of the variable found + DataSize Size of Data found. If size is less than the + data, this value contains the required size. + Data Data pointer + +Returns: + + EFI STATUS + +--*/ +{ + VARIABLE_POINTER_TRACK Variable; + UINTN VarDataSize; + EFI_STATUS Status; + + if (VariableName == NULL || VendorGuid == NULL || DataSize == NULL) { + return EFI_INVALID_PARAMETER; + } + + // + // Find existing variable + // + Status = FindVariable (VariableName, VendorGuid, &Variable); + + if (Variable.CurrPtr == NULL || EFI_ERROR (Status)) { + return Status; + } + // + // Get data size + // + VarDataSize = Variable.CurrPtr->DataSize; + if (*DataSize >= VarDataSize) { + if (Data == NULL) { + return EFI_INVALID_PARAMETER; + } + CopyMem (Data, GetVariableDataPtr (Variable.CurrPtr), VarDataSize); + + if (Attributes != NULL) { + *Attributes = Variable.CurrPtr->Attributes; + } + + *DataSize = VarDataSize; + + return EFI_SUCCESS; + } else { + *DataSize = VarDataSize; + return EFI_BUFFER_TOO_SMALL; + } +} + +EFI_STATUS +EFIAPI +GetNextVariableName ( + IN OUT UINTN *VariableNameSize, + IN OUT CHAR16 *VariableName, + IN OUT EFI_GUID *VendorGuid + ) +/*++ + +Routine Description: + + This code Finds the Next available variable + +Arguments: + + VariableNameSize Size of the variable + VariableName Pointer to variable name + VendorGuid Variable Vendor Guid + +Returns: + + EFI STATUS + +--*/ +{ + VARIABLE_POINTER_TRACK Variable; + UINTN VarNameSize; + EFI_STATUS Status; + + if (VariableNameSize == NULL || VariableName == NULL || VendorGuid == NULL) { + return EFI_INVALID_PARAMETER; + } + + Status = FindVariable (VariableName, VendorGuid, &Variable); + + if (Variable.CurrPtr == NULL || EFI_ERROR (Status)) { + return Status; + } + + if (VariableName[0] != 0) { + // + // If variable name is not NULL, get next variable + // + Variable.CurrPtr = GetNextVariablePtr (Variable.CurrPtr); + } + + while (TRUE) { + // + // The order we find variable is: 1). NonVolatile; 2). Volatile + // If both volatile and non-volatile variable store are parsed, + // return not found + // + if (Variable.CurrPtr >= Variable.EndPtr || Variable.CurrPtr == NULL) { + if (Variable.Type == Volatile) { + // + // Since we met the end of Volatile storage, we have parsed all the stores. + // + return EFI_NOT_FOUND; + } + + // + // End of NonVolatile, continue to parse Volatile + // + Variable.Type = Volatile; + Variable.StartPtr = (VARIABLE_HEADER *) ((VARIABLE_STORE_HEADER *) mGlobal->VariableBase[Volatile] + 1); + Variable.EndPtr = (VARIABLE_HEADER *) GetEndPointer ((VARIABLE_STORE_HEADER *) mGlobal->VariableBase[Volatile]); + + Variable.CurrPtr = Variable.StartPtr; + if (!IsValidVariableHeader (Variable.CurrPtr)) { + continue; + } + } + // + // Variable is found + // + if (IsValidVariableHeader (Variable.CurrPtr) && + ((Variable.CurrPtr->State == VAR_ADDED) || + (Variable.CurrPtr->State == (VAR_ADDED & VAR_IN_DELETED_TRANSITION)))) { + if (!EfiAtRuntime () || (Variable.CurrPtr->Attributes & EFI_VARIABLE_RUNTIME_ACCESS)) { + VarNameSize = Variable.CurrPtr->NameSize; + if (VarNameSize <= *VariableNameSize) { + CopyMem ( + VariableName, + GET_VARIABLE_NAME_PTR (Variable.CurrPtr), + VarNameSize + ); + CopyMem ( + VendorGuid, + &Variable.CurrPtr->VendorGuid, + sizeof (EFI_GUID) + ); + Status = EFI_SUCCESS; + } else { + Status = EFI_BUFFER_TOO_SMALL; + } + + *VariableNameSize = VarNameSize; + return Status; + } + } + + Variable.CurrPtr = GetNextVariablePtr (Variable.CurrPtr); + } +} + +EFI_STATUS +EFIAPI +SetVariable ( + IN CHAR16 *VariableName, + IN EFI_GUID *VendorGuid, + IN UINT32 Attributes, + IN UINTN DataSize, + IN VOID *Data + ) +/*++ + +Routine Description: + + This code sets variable in storage blocks (Volatile or Non-Volatile) + +Arguments: + + VariableName Name of Variable to be found + VendorGuid Variable vendor GUID + Attributes Attribute value of the variable found + DataSize Size of Data found. If size is less than the + data, this value contains the required size. + Data Data pointer + +Returns: + + EFI_INVALID_PARAMETER - Invalid parameter + EFI_SUCCESS - Set successfully + EFI_OUT_OF_RESOURCES - Resource not enough to set variable + EFI_NOT_FOUND - Not found + EFI_DEVICE_ERROR - Variable can not be saved due to hardware failure + EFI_WRITE_PROTECTED - Variable is read-only + +--*/ +{ + VARIABLE_POINTER_TRACK Variable; + EFI_STATUS Status; + + // + // Check input parameters + // + if (VariableName == NULL || VariableName[0] == 0 || VendorGuid == NULL) { + return EFI_INVALID_PARAMETER; + } + + if (DataSize != 0 && Data == NULL) { + return EFI_INVALID_PARAMETER; + } + + // + // Not support authenticated variable write yet. + // + if ((Attributes & EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS) != 0) { + 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 PcdGet32 (PcdMaxHardwareErrorVariableSize) + // bytes for HwErrRec, and PcdGet32 (PcdMaxVariableSize) bytes for the others. + // + if ((Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == EFI_VARIABLE_HARDWARE_ERROR_RECORD) { + if ((DataSize > PcdGet32(PcdMaxHardwareErrorVariableSize)) || + (sizeof (VARIABLE_HEADER) + StrSize (VariableName) + DataSize > PcdGet32(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 { + if ((DataSize > PcdGet32(PcdMaxVariableSize)) || + (sizeof (VARIABLE_HEADER) + StrSize (VariableName) + DataSize > PcdGet32(PcdMaxVariableSize))) { + return EFI_INVALID_PARAMETER; + } + } + + // + // Check whether the input variable is already existed + // + Status = FindVariable (VariableName, VendorGuid, &Variable); + + // + // Hook the operation of setting PlatformLangCodes/PlatformLang and LangCodes/Lang + // + AutoUpdateLangVariable (VariableName, Data, DataSize); + + Status = UpdateVariable (VariableName, VendorGuid, Data, DataSize, Attributes, &Variable); + + return Status; +} + EFI_STATUS EFIAPI QueryVariableInfo ( @@ -1023,27 +1605,22 @@ Returns: 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; } -#if (EFI_SPECIFICATION_VERSION >= 0x0002000A) if((Attributes & (EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_HARDWARE_ERROR_RECORD)) == 0) { // // Make sure the Attributes combination is supported by the platform. // return EFI_UNSUPPORTED; - } -#else - if((Attributes & (EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS)) == 0) { - // - // Make sure the Attributes combination is supported by the platform. - // - return EFI_UNSUPPORTED; - } -#endif - else if ((Attributes & (EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS)) == EFI_VARIABLE_RUNTIME_ACCESS) { + } else if ((Attributes & (EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS)) == EFI_VARIABLE_RUNTIME_ACCESS) { // // Make sure if runtime bit is set, boot service bit is set also. // @@ -1053,7 +1630,17 @@ Returns: // 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; + } else if ((Attributes & EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS) != 0) { + // + // Not support authentiated variable write yet. + // + return EFI_UNSUPPORTED; + } VariableStoreHeader = (VARIABLE_STORE_HEADER *) mGlobal->VariableBase[ (Attributes & EFI_VARIABLE_NON_VOLATILE) ? NonVolatile : Volatile @@ -1063,21 +1650,24 @@ Returns: // 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 MAX_VARIABLE_SIZE with the exception of the variable header size. - // - *MaximumVariableSize = MAX_VARIABLE_SIZE - sizeof (VARIABLE_HEADER); - -#if (EFI_SPECIFICATION_VERSION >= 0x0002000A) // // Harware error record variable needs larger size. // - if ((Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == EFI_VARIABLE_HARDWARE_ERROR_RECORD) { - *MaximumVariableSize = MAX_HARDWARE_ERROR_VARIABLE_SIZE - sizeof (VARIABLE_HEADER); + if ((Attributes & (EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_HARDWARE_ERROR_RECORD)) == (EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_HARDWARE_ERROR_RECORD)) { + *MaximumVariableStorageSize = PcdGet32(PcdHwErrStorageSize); + *MaximumVariableSize = PcdGet32(PcdMaxHardwareErrorVariableSize) - sizeof (VARIABLE_HEADER); + } else { + if ((Attributes & EFI_VARIABLE_NON_VOLATILE) != 0) { + ASSERT (PcdGet32(PcdHwErrStorageSize) < VariableStoreHeader->Size); + *MaximumVariableStorageSize = VariableStoreHeader->Size - sizeof (VARIABLE_STORE_HEADER) - PcdGet32(PcdHwErrStorageSize); + } + + // + // Let *MaximumVariableSize be PcdGet32(PcdMaxVariableSize) with the exception of the variable header size. + // + *MaximumVariableSize = PcdGet32(PcdMaxVariableSize) - sizeof (VARIABLE_HEADER); } -#endif // // Point to the starting address of the variables. @@ -1087,7 +1677,7 @@ Returns: // // Now walk through the related variable store. // - while (IsValidVariableHeader (Variable) && (Variable < GetEndPointer (VariableStoreHeader))) { + while ((Variable < GetEndPointer (VariableStoreHeader)) && IsValidVariableHeader (Variable)) { NextVariable = GetNextVariablePtr (Variable); VariableSize = (UINT64) (UINTN) NextVariable - (UINT64) (UINTN) Variable; @@ -1098,15 +1688,22 @@ Returns: // since the space occupied by variables not marked with // VAR_ADDED is not allowed to be reclaimed in Runtime. // - *RemainingVariableStorageSize -= VariableSize; + if ((NextVariable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == EFI_VARIABLE_HARDWARE_ERROR_RECORD) { + HwErrVariableTotalSize += VariableSize; + } else { + CommonVariableTotalSize += VariableSize; + } } else { // // Only care about Variables with State VAR_ADDED,because // the space not marked as VAR_ADDED is reclaimable now. // - if ((Variable->State == VAR_ADDED) || - (Variable->State == (VAR_ADDED & VAR_IN_DELETED_TRANSITION))) { - *RemainingVariableStorageSize -= VariableSize; + if ((Variable->State == VAR_ADDED) || (Variable->State == (VAR_ADDED & VAR_IN_DELETED_TRANSITION))) { + if ((NextVariable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == EFI_VARIABLE_HARDWARE_ERROR_RECORD) { + HwErrVariableTotalSize += VariableSize; + } else { + CommonVariableTotalSize += VariableSize; + } } } @@ -1116,15 +1713,14 @@ Returns: Variable = NextVariable; } - if (*RemainingVariableStorageSize < sizeof (VARIABLE_HEADER)) { - *MaximumVariableSize = 0; - } else if ((*RemainingVariableStorageSize - sizeof (VARIABLE_HEADER)) < *MaximumVariableSize) { - *MaximumVariableSize = *RemainingVariableStorageSize - sizeof (VARIABLE_HEADER); + if ((Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == EFI_VARIABLE_HARDWARE_ERROR_RECORD){ + *RemainingVariableStorageSize = *MaximumVariableStorageSize - HwErrVariableTotalSize; + } else { + *RemainingVariableStorageSize = *MaximumVariableStorageSize - CommonVariableTotalSize; } return EFI_SUCCESS; } -#endif EFI_STATUS EFIAPI @@ -1154,12 +1750,12 @@ Returns: EFI_STATUS Status; EFI_HANDLE NewHandle; VS_DEV *Dev; - VOID *HobList; + EFI_PEI_HOB_POINTERS GuidHob; + VARIABLE_HEADER *Variable; VARIABLE_HEADER *NextVariable; VARIABLE_STORE_HEADER *VariableStoreHeader; EFI_FLASH_MAP_FS_ENTRY_DATA *FlashMapEntryData; EFI_FLASH_SUBAREA_ENTRY VariableStoreEntry; - VOID *Buffer; UINT64 BaseAddress; UINT64 Length; EFI_GCD_MEMORY_SPACE_DESCRIPTOR GcdDescriptor; @@ -1167,38 +1763,35 @@ Returns: Status = gBS->AllocatePool ( EfiRuntimeServicesData, (UINTN) sizeof (VARIABLE_GLOBAL), - &mGlobal + (VOID**) &mGlobal ); if (EFI_ERROR (Status)) { return Status; } - Status = EfiGetSystemConfigurationTable (&gEfiHobListGuid, &HobList); + ZeroMem (mGlobal, (UINTN) sizeof (VARIABLE_GLOBAL)); - if (EFI_ERROR (Status)) { - return Status; - } - - - for (FlashMapEntryData = NULL; ;) { - Buffer = GetNextGuidHob (&gEfiFlashMapHobGuid, &HobList); - - FlashMapEntryData = (EFI_FLASH_MAP_FS_ENTRY_DATA *) Buffer; - - // - // Get the variable store area - // + GuidHob.Raw = GetHobList (); + FlashMapEntryData = NULL; + while ((GuidHob.Raw = GetNextGuidHob (&gEfiFlashMapHobGuid, GuidHob.Raw)) != NULL) { + FlashMapEntryData = (EFI_FLASH_MAP_FS_ENTRY_DATA *) GET_GUID_HOB_DATA (GuidHob.Guid); if (FlashMapEntryData->AreaType == EFI_FLASH_AREA_EFI_VARIABLES) { break; } + GuidHob.Raw = GET_NEXT_HOB (GuidHob); } - if (EFI_ERROR (Status) || FlashMapEntryData == NULL) { + if (FlashMapEntryData == NULL) { + DEBUG ((EFI_D_ERROR, "FSVariable: Could not find flash area for variable!\n")); Status = EFI_NOT_FOUND; return Status; } - - VariableStoreEntry = FlashMapEntryData->Entries[0]; + + CopyMem( + (VOID*)&VariableStoreEntry, + (VOID*)&FlashMapEntryData->Entries[0], + sizeof(EFI_FLASH_SUBAREA_ENTRY) + ); // // Mark the variable storage region of the FLASH as RUNTIME @@ -1220,7 +1813,7 @@ Returns: Status = EFI_UNSUPPORTED; return Status; } - + Status = FileStorageConstructor ( &mGlobal->VariableStore[NonVolatile], &mGlobal->GoVirtualChildEvent[NonVolatile], @@ -1264,12 +1857,21 @@ Returns: // // Calculate LastVariableOffset // - NextVariable = (VARIABLE_HEADER *) (VariableStoreHeader + 1); - while (IsValidVariableHeader (NextVariable)) { - NextVariable = GetNextVariablePtr (NextVariable); + Variable = (VARIABLE_HEADER *) (VariableStoreHeader + 1); + while (IsValidVariableHeader (Variable)) { + UINTN VariableSize = 0; + NextVariable = GetNextVariablePtr (Variable); + VariableSize = NextVariable - Variable; + if ((NextVariable->Attributes & (EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_HARDWARE_ERROR_RECORD)) == (EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_HARDWARE_ERROR_RECORD)) { + mGlobal->HwErrVariableTotalSize += HEADER_ALIGN (VariableSize); + } else { + mGlobal->CommonVariableTotalSize += HEADER_ALIGN (VariableSize); + } + Variable = NextVariable; } - mGlobal->LastVariableOffset[NonVolatile] = (UINTN) NextVariable - (UINTN) VariableStoreHeader; - mGlobal->VariableBase[NonVolatile] = VariableStoreHeader; + + mGlobal->LastVariableOffset[NonVolatile] = (UINTN) Variable - (UINTN) VariableStoreHeader; + mGlobal->VariableBase[NonVolatile] = VariableStoreHeader; // // Reclaim if remaining space is too small @@ -1281,7 +1883,7 @@ Returns: // Reclaim error // we cannot restore to original state // - DEBUG ((EFI_D_ERROR, "FSVariable: Recalim error (fetal error) - %r\n", Status)); + DEBUG ((EFI_D_ERROR, "FSVariable: Reclaim error (fatal error) - %r\n", Status)); ASSERT_EFI_ERROR (Status); } } @@ -1305,13 +1907,11 @@ Returns: ); - SystemTable->RuntimeServices->GetVariable = GetVariable; + SystemTable->RuntimeServices->GetVariable = DuetGetVariable; SystemTable->RuntimeServices->GetNextVariableName = GetNextVariableName; SystemTable->RuntimeServices->SetVariable = SetVariable; -#if (EFI_SPECIFICATION_VERSION >= 0x00020000) SystemTable->RuntimeServices->QueryVariableInfo = QueryVariableInfo; -#endif // // Now install the Variable Runtime Architectural Protocol on a new handle @@ -1328,18 +1928,13 @@ Returns: ASSERT_EFI_ERROR (Status); return Status; - -//Shutdown: -// EfiShutdownRuntimeDriverLib (); -// return Status; } -STATIC VOID EFIAPI -OnVirtualAddressChange ( +OnVirtualAddressChangeFsv ( IN EFI_EVENT Event, IN VOID *Context ) @@ -1348,9 +1943,12 @@ OnVirtualAddressChange ( for (Index = 0; Index < MaxType; Index++) { mGlobal->GoVirtualChildEvent[Index] (Event, mGlobal->VariableStore[Index]); - EfiConvertPointer (0, &mGlobal->VariableStore[Index]); + EfiConvertPointer (0, (VOID**) &mGlobal->VariableStore[Index]); EfiConvertPointer (0, &mGlobal->VariableBase[Index]); } + EfiConvertPointer (0, (VOID **) &mGlobal->PlatformLangCodes); + EfiConvertPointer (0, (VOID **) &mGlobal->LangCodes); + EfiConvertPointer (0, (VOID **) &mGlobal->PlatformLang); EfiConvertPointer (0, &mGlobal->Scratch); - EfiConvertPointer (0, &mGlobal); + EfiConvertPointer (0, (VOID**) &mGlobal); }