From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from mga05.intel.com (mga05.intel.com [192.55.52.43]) by mx.groups.io with SMTP id smtpd.web12.7141.1654754624109050740 for ; Wed, 08 Jun 2022 23:03:46 -0700 Authentication-Results: mx.groups.io; dkim=fail reason="unable to parse pub key" header.i=@intel.com header.s=intel header.b=Tq5nZ8HB; spf=pass (domain: intel.com, ip: 192.55.52.43, mailfrom: judah.vang@intel.com) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1654754626; x=1686290626; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=dT/WC3NhmnwY1IL5Mqd4BeJoQyqMhgD47HA52x7L4io=; b=Tq5nZ8HB98etjLVe1Hk6tMJoxPBiE0odmgIfYJu8pIKkaW+yDGSx+zLa 1hSMgI+iMUkTIJrccUjkXhxviOi7wi2czdwPq0yhOcO7mcnt5odx6rlxG 2OhBB1BD7+3MW8iidVllIijrdo2Gqouyp5ljEyYOAaCYKRP9XUz6wpuVK yiUJ3LFgkX27FNOodiRDMo0GJnuZvvVL91J7BZon2craIoyJP8XKA16uX XKLNcR1OABIXQeB7ah1kZnnt1nT193vyY5C2EuerD7mCjj6HvStE61MqR WdWCz9XEEoR4XevSqdVEWgA/YCFJStRKaWHH4WHZoFNRNOZ3BHGaO6dnH w==; X-IronPort-AV: E=McAfee;i="6400,9594,10372"; a="363487914" X-IronPort-AV: E=Sophos;i="5.91,287,1647327600"; d="scan'208";a="363487914" Received: from orsmga002.jf.intel.com ([10.7.209.21]) by fmsmga105.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 08 Jun 2022 23:03:45 -0700 X-IronPort-AV: E=Sophos;i="5.91,287,1647327600"; d="scan'208";a="566239832" Received: from jvang-mobl.amr.corp.intel.com ([10.209.91.16]) by orsmga002-auth.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 08 Jun 2022 23:03:44 -0700 From: "Judah Vang" To: devel@edk2.groups.io Cc: Jian J Wang , Liming Gao , Hao A Wu , Nishant C Mistry Subject: [PATCH v3 08/28] MdeModulePkg: Add new Variable functionality Date: Wed, 8 Jun 2022 23:03:02 -0700 Message-Id: <20220609060322.3491-9-judah.vang@intel.com> X-Mailer: git-send-email 2.35.1.windows.2 In-Reply-To: <20220609060322.3491-1-judah.vang@intel.com> References: <20220609060322.3491-1-judah.vang@intel.com> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit REF: https://bugzilla.tianocore.org/show_bug.cgi?id=2594 V3: Update GetNvVariableStore() to call GetVariableFlashNvStorageInfo() and SafeUint64ToUint32(). V1: Provide new APIs for retrieving variable information. Add new function stubs for retrieving Protected variable information. Cc: Jian J Wang Cc: Liming Gao Cc: Hao A Wu Cc: Nishant C Mistry Signed-off-by: Jian J Wang Signed-off-by: Nishant C Mistry Signed-off-by: Judah Vang --- MdeModulePkg/Universal/Variable/Pei/VariablePei.inf | 10 +- MdeModulePkg/Universal/Variable/Pei/Variable.h | 80 +- MdeModulePkg/Universal/Variable/Pei/VariableParsing.h | 309 +++++++ MdeModulePkg/Universal/Variable/Pei/VariableStore.h | 116 +++ MdeModulePkg/Universal/Variable/Pei/Variable.c | 890 +++--------------- MdeModulePkg/Universal/Variable/Pei/VariableParsing.c | 941 ++++++++++++++++++++ MdeModulePkg/Universal/Variable/Pei/VariableStore.c | 307 +++++++ 7 files changed, 1893 insertions(+), 760 deletions(-) diff --git a/MdeModulePkg/Universal/Variable/Pei/VariablePei.inf b/MdeModulePkg/Universal/Variable/Pei/VariablePei.inf index 7264a24bdf71..0945b4dec435 100644 --- a/MdeModulePkg/Universal/Variable/Pei/VariablePei.inf +++ b/MdeModulePkg/Universal/Variable/Pei/VariablePei.inf @@ -3,7 +3,7 @@ # # This module implements ReadOnly Variable Services required by PEIM and installs PEI ReadOnly Varaiable2 PPI. # -# Copyright (c) 2006 - 2019, Intel Corporation. All rights reserved.
+# Copyright (c) 2006 - 2022, Intel Corporation. All rights reserved.
# SPDX-License-Identifier: BSD-2-Clause-Patent # ## @@ -26,6 +26,10 @@ [Defines] [Sources] Variable.c Variable.h + VariableStore.c + VariableStore.h + VariableParsing.c + VariableParsing.h [Packages] MdePkg/MdePkg.dec @@ -41,6 +45,7 @@ [LibraryClasses] PeiServicesLib SafeIntLib VariableFlashInfoLib + ProtectedVariableLib [Guids] ## CONSUMES ## GUID # Variable store header @@ -58,7 +63,8 @@ [Guids] gEdkiiFaultTolerantWriteGuid [Ppis] - gEfiPeiReadOnlyVariable2PpiGuid ## PRODUCES + gEfiPeiReadOnlyVariable2PpiGuid ## PRODUCES + gEfiPeiVariableStoreDiscoveredPpiGuid ## CONSUMES [Pcd] gEfiMdeModulePkgTokenSpaceGuid.PcdEmuVariableNvModeEnable ## SOMETIMES_CONSUMES diff --git a/MdeModulePkg/Universal/Variable/Pei/Variable.h b/MdeModulePkg/Universal/Variable/Pei/Variable.h index 51effbf79987..8c79ff850b38 100644 --- a/MdeModulePkg/Universal/Variable/Pei/Variable.h +++ b/MdeModulePkg/Universal/Variable/Pei/Variable.h @@ -2,7 +2,7 @@ The internal header file includes the common header files, defines internal structure and functions used by PeiVariable module. -Copyright (c) 2006 - 2017, Intel Corporation. All rights reserved.
+Copyright (c) 2006 - 2022, Intel Corporation. All rights reserved.
SPDX-License-Identifier: BSD-2-Clause-Patent **/ @@ -22,11 +22,13 @@ SPDX-License-Identifier: BSD-2-Clause-Patent #include #include #include +#include #include #include #include #include +#include typedef enum { VariableStoreTypeHob, @@ -144,4 +146,80 @@ PeiGetNextVariableName ( IN OUT EFI_GUID *VariableGuid ); +/** + This service retrieves a variable's value using its name and GUID. + + Read the specified variable from the UEFI variable store. If the Data + buffer is too small to hold the contents of the variable, the error + EFI_BUFFER_TOO_SMALL is returned and DataSize is set to the required buffer + size to obtain the data. + + @param This A pointer to this instance of the EFI_PEI_READ_ONLY_VARIABLE2_PPI. + @param VariableName A pointer to a null-terminated string that is the variable's name. + @param VariableGuid A pointer to an EFI_GUID that is the variable's GUID. The combination of + VariableGuid and VariableName must be unique. + @param Attributes If non-NULL, on return, points to the variable's attributes. + @param DataSize On entry, points to the size in bytes of the Data buffer. + On return, points to the size of the data returned in Data. + @param Data Points to the buffer which will hold the returned variable value. + May be NULL with a zero DataSize in order to determine the size of the buffer needed. + + @retval EFI_SUCCESS The variable was read successfully. + @retval EFI_NOT_FOUND The variable was not found. + @retval EFI_BUFFER_TOO_SMALL The DataSize is too small for the resulting data. + DataSize is updated with the size required for + the specified variable. + @retval EFI_INVALID_PARAMETER VariableName, VariableGuid, DataSize or Data is NULL. + @retval EFI_DEVICE_ERROR The variable could not be retrieved because of a device error. + +**/ +EFI_STATUS +EFIAPI +PeiGetVariableEx ( + IN CONST EFI_PEI_READ_ONLY_VARIABLE2_PPI *This, + IN CONST CHAR16 *VariableName, + IN CONST EFI_GUID *VariableGuid, + OUT UINT32 *Attributes, + IN OUT UINTN *DataSize, + OUT VOID *Data OPTIONAL + ); + +/** + Return the next variable name and GUID. + + This function is called multiple times to retrieve the VariableName + and VariableGuid of all variables currently available in the system. + On each call, the previous results are passed into the interface, + and, on return, the interface returns the data for the next + interface. When the entire variable list has been returned, + EFI_NOT_FOUND is returned. + + @param This A pointer to this instance of the EFI_PEI_READ_ONLY_VARIABLE2_PPI. + + @param VariableNameSize On entry, points to the size of the buffer pointed to by VariableName. + @param VariableName On entry, a pointer to a null-terminated string that is the variable's name. + On return, points to the next variable's null-terminated name string. + + @param VariableGuid On entry, a pointer to an UEFI _GUID that is the variable's GUID. + On return, a pointer to the next variable's GUID. + + @retval EFI_SUCCESS The variable was read successfully. + @retval EFI_NOT_FOUND The variable could not be found. + @retval EFI_BUFFER_TOO_SMALL The VariableNameSize is too small for the resulting + data. VariableNameSize is updated with the size + required for the specified variable. + @retval EFI_INVALID_PARAMETER VariableName, VariableGuid or + VariableNameSize is NULL. + @retval EFI_DEVICE_ERROR The variable could not be retrieved because of a device error. + +**/ +EFI_STATUS +EFIAPI +PeiGetNextVariableNameEx ( + IN CONST EFI_PEI_READ_ONLY_VARIABLE2_PPI *This, + IN OUT UINTN *VariableNameSize, + IN OUT CHAR16 *VariableName, + IN OUT EFI_GUID *VariableGuid + ); + #endif diff --git a/MdeModulePkg/Universal/Variable/Pei/VariableParsing.h b/MdeModulePkg/Universal/Variable/Pei/VariableParsing.h new file mode 100644 index 000000000000..d7af6cb6e8be --- /dev/null +++ b/MdeModulePkg/Universal/Variable/Pei/VariableParsing.h @@ -0,0 +1,309 @@ +/** @file + The internal header file includes the common header files, defines + internal structure and functions used by PeiVariable module. + +Copyright (c) 2022, Intel Corporation. All rights reserved.
+SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef PEI_VARIABLE_PARSING_H_ +#define PEI_VARIABLE_PARSING_H_ + +#include "Variable.h" + +/** + + Gets the pointer to the first variable header in given variable store area. + + @param[in] VarStoreHeader Pointer to the Variable Store Header. + + @return Pointer to the first variable header. + +**/ +VARIABLE_HEADER * +GetStartPointer ( + IN VARIABLE_STORE_HEADER *VarStoreHeader + ); + +/** + + Gets the pointer to the end of the variable storage area. + + This function gets pointer to the end of the variable storage + area, according to the input variable store header. + + @param[in] VarStoreHeader Pointer to the Variable Store Header. + + @return Pointer to the end of the variable storage area. + +**/ +VARIABLE_HEADER * +GetEndPointer ( + IN VARIABLE_STORE_HEADER *VarStoreHeader + ); + +/** + This code checks if variable header is valid or not. + + @param[in] Variable Pointer to the Variable Header. + + @retval TRUE Variable header is valid. + @retval FALSE Variable header is not valid. + +**/ +BOOLEAN +IsValidVariableHeader ( + IN VARIABLE_HEADER *Variable + ); + +/** + This code gets the pointer to the next variable header. + + @param[in] StoreInfo Pointer to variable store info structure. + @param[in] Variable Pointer to the Variable Header. + @param[in] VariableHeader Pointer to the Variable Header that has consecutive content. + + @return A VARIABLE_HEADER* pointer to next variable header. + +**/ +VARIABLE_HEADER * +GetNextVariablePtr ( + IN VARIABLE_STORE_INFO *StoreInfo, + IN VARIABLE_HEADER *Variable, + IN VARIABLE_HEADER *VariableHeader + ); + +/** + This code gets the pointer to the variable guid. + + @param[in] Variable Pointer to the Variable Header. + @param[in] AuthFlag Authenticated variable flag. + + @return A EFI_GUID* pointer to Vendor Guid. + +**/ +EFI_GUID * +GetVendorGuidPtr ( + IN VARIABLE_HEADER *Variable, + IN BOOLEAN AuthFlag + ); + +/** + This code gets the pointer to the variable name. + + @param[in] Variable Pointer to the Variable Header. + @param[in] AuthFlag Authenticated variable flag. + + @return A CHAR16* pointer to Variable Name. + +**/ +CHAR16 * +GetVariableNamePtr ( + IN VARIABLE_HEADER *Variable, + IN BOOLEAN AuthFlag + ); + +/** + This code gets the size of name of variable. + + @param[in] Variable Pointer to the Variable Header. + @param[in] AuthFlag Authenticated variable flag. + + @return Size of variable in bytes in type UINTN. + +**/ +UINTN +NameSizeOfVariable ( + IN VARIABLE_HEADER *Variable, + IN BOOLEAN AuthFlag + ); + +/** + This code gets the size of data of variable. + + @param[in] Variable Pointer to the Variable Header. + @param[in] AuthFlag Authenticated variable flag. + + @return Size of variable in bytes in type UINTN. + +**/ +UINTN +DataSizeOfVariable ( + IN VARIABLE_HEADER *Variable, + IN BOOLEAN AuthFlag + ); + +/** + This code gets the pointer to the variable data. + + @param[in] Variable Pointer to the Variable Header. + @param[in] VariableHeader Pointer to the Variable Header that has consecutive content. + @param[in] AuthFlag Authenticated variable flag. + + @return A UINT8* pointer to Variable Data. + +**/ +UINT8 * +GetVariableDataPtr ( + IN VARIABLE_HEADER *Variable, + IN VARIABLE_HEADER *VariableHeader, + IN BOOLEAN AuthFlag + ); + +/** + Get variable header that has consecutive content. + + @param[in] StoreInfo Pointer to variable store info structure. + @param[in] Variable Pointer to the Variable Header. + @param[out] VariableHeader Pointer to Pointer to the Variable Header that has consecutive content. + + @retval TRUE Variable header is valid. + @retval FALSE Variable header is not valid. + +**/ +BOOLEAN +GetVariableHeader ( + IN VARIABLE_STORE_INFO *StoreInfo, + IN VARIABLE_HEADER *Variable, + OUT VARIABLE_HEADER **VariableHeader + ); + +/** + This code gets the size of variable header. + + @param[in] AuthFlag Authenticated variable flag. + + @return Size of variable header in bytes in type UINTN. + +**/ +UINTN +GetVariableHeaderSize ( + IN BOOLEAN AuthFlag + ); + +/** + Get variable name or data to output buffer. + + @param[in] StoreInfo Pointer to variable store info structure. + @param[in] NameOrData Pointer to the variable name/data that may be inconsecutive. + @param[in] Size Variable name/data size. + @param[out] Buffer Pointer to output buffer to hold the variable name/data. + +**/ +VOID +GetVariableNameOrData ( + IN VARIABLE_STORE_INFO *StoreInfo, + IN UINT8 *NameOrData, + IN UINTN Size, + OUT UINT8 *Buffer + ); + +/** + This function compares a variable with variable entries in database. + + @param[in] StoreInfo Pointer to variable store info structure. + @param[in] Variable Pointer to the variable in our database + @param[in] VariableHeader Pointer to the Variable Header that has consecutive content. + @param[in] VariableName Name of the variable to compare to 'Variable' + @param[in] VendorGuid GUID of the variable to compare to 'Variable' + @param[out] PtrTrack Variable Track Pointer structure that contains Variable Information. + + @retval EFI_SUCCESS Found match variable + @retval EFI_NOT_FOUND Variable not found + +**/ +EFI_STATUS +CompareWithValidVariable ( + IN VARIABLE_STORE_INFO *StoreInfo, + IN VARIABLE_HEADER *Variable, + IN VARIABLE_HEADER *VariableHeader, + IN CONST CHAR16 *VariableName, + IN CONST EFI_GUID *VendorGuid, + OUT VARIABLE_POINTER_TRACK *PtrTrack + ); + +/** + + Retrieve details of the variable next to given variable within VariableStore. + + If VarInfo->Address is NULL, the first one in VariableStore is returned. + + VariableStart and/or VariableEnd can be given optionally for the situation + in which the valid storage space is smaller than the VariableStore->Size. + This usually happens when PEI variable services make a compact variable + cache to save memory, which cannot make use VariableStore->Size to determine + the correct variable storage range. + + @param[in,out] VariableInfo Pointer to variable information. + + @retval EFI_INVALID_PARAMETER VariableInfo or VariableStore is NULL. + @retval EFI_NOT_FOUND If the end of VariableStore is reached. + @retval EFI_SUCCESS The next variable is retrieved successfully. + +**/ +EFI_STATUS +EFIAPI +GetNextVariableInfo ( + IN OUT PROTECTED_VARIABLE_INFO *VariableInfo + ); + +/** + + Retrieve details about a variable and return them in VariableInfo->Header. + + If VariableInfo->Address is given, this function will calculate its offset + relative to given variable storage via VariableStore; Otherwise, it will try + other internal variable storages or cached copies. It's assumed that, for all + copies of NV variable storage, all variables are stored in the same relative + position. If VariableInfo->Address is found in the range of any storage copies, + its offset relative to that storage should be the same in other copies. + + If VariableInfo->Offset is given (non-zero) but not VariableInfo->Address, + this function will return the variable memory address inside VariableStore, + if given, via VariableInfo->Address; Otherwise, the address of other storage + copies will be returned, if any. + + For a new variable whose offset has not been determined, a value of -1 as + VariableInfo->Offset should be passed to skip the offset calculation. + + @param[in,out] VariableInfo Pointer to variable information. + + @retval EFI_INVALID_PARAMETER VariableInfo is NULL or both VariableInfo->Address + and VariableInfo->Offset are NULL (0). + @retval EFI_NOT_FOUND If given Address or Offset is out of range of + any given or internal storage copies. + @retval EFI_SUCCESS Variable details are retrieved successfully. + +**/ +EFI_STATUS +EFIAPI +GetVariableInfo ( + IN OUT PROTECTED_VARIABLE_INFO *VariableInfo + ); + +/** + + Find variable specified with input parameters. + + @param[in] StoreInfo Pointer to variable information. + @param[in] VariableName Pointer to variable name. + @param[in] VendorGuid Pointer to variable GUID. + @param[in] PtrTrack Pointer to variable track. + + @retval EFI_INVALID_PARAMETER VariableInfo is NULL or both VariableInfo->Address + and VariableInfo->Offset are NULL (0). + @retval EFI_NOT_FOUND If given Address or Offset is out of range of + any given or internal storage copies. + @retval EFI_SUCCESS Variable details are retrieved successfully. + +**/ +EFI_STATUS +FindVariableEx ( + IN VARIABLE_STORE_INFO *StoreInfo, + IN CONST CHAR16 *VariableName, + IN CONST EFI_GUID *VendorGuid, + OUT VARIABLE_POINTER_TRACK *PtrTrack + ); + +#endif diff --git a/MdeModulePkg/Universal/Variable/Pei/VariableStore.h b/MdeModulePkg/Universal/Variable/Pei/VariableStore.h new file mode 100644 index 000000000000..6e2f6f939bab --- /dev/null +++ b/MdeModulePkg/Universal/Variable/Pei/VariableStore.h @@ -0,0 +1,116 @@ +/** @file + Implement ReadOnly Variable Services required by PEIM and install + PEI ReadOnly Varaiable2 PPI. These services operates the non volatile storage space. + +Copyright (c) 2022, Intel Corporation. All rights reserved.
+SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef PEI_VARIABLE_STORE_H_ +#define PEI_VARIABLE_STORE_H_ + +/** + Get variable store status. + + @param[in] VarStoreHeader Pointer to the Variable Store Header. + + @retval EfiRaw Variable store is raw + @retval EfiValid Variable store is valid + @retval EfiInvalid Variable store is invalid + +**/ +VARIABLE_STORE_STATUS +GetVariableStoreStatus ( + IN VARIABLE_STORE_HEADER *VarStoreHeader + ); + +/** + Reports HOB variable store is available or not. + + @retval EFI_NOT_READY HOB variable store info not available. + @retval EFI_NOT_FOUND HOB variable store is NOT available. + @retval EFI_SUCCESS HOB variable store is available. +**/ +EFI_STATUS +EFIAPI +IsHobVariableStoreAvailable ( + VOID + ); + +/** + Get HOB variable store. + + @param[out] StoreInfo Return the store info. + +**/ +VOID +GetHobVariableStore ( + OUT VARIABLE_STORE_INFO *StoreInfo + ); + +/** + Get NV variable store. + + @param[out] StoreInfo Return the store info. + @param[out] VariableStoreHeader Return header of FV containing the store. + +**/ +VOID +GetNvVariableStore ( + OUT VARIABLE_STORE_INFO *StoreInfo, + OUT EFI_FIRMWARE_VOLUME_HEADER **VariableFvHeader + ); + +/** + Return the variable store header and the store info based on the Index. + + @param[in] Type The type of the variable store. + @param[out] StoreInfo Return the store info. + + @return Pointer to the variable store header. +**/ +VARIABLE_STORE_HEADER * +GetVariableStore ( + IN VARIABLE_STORE_TYPE Type, + OUT VARIABLE_STORE_INFO *StoreInfo + ); + +/** + Make a cached copy of NV variable storage. + + To save memory in PEI phase, only valid variables are copied into cache. + An IndexTable could be used to store the offset (relative to NV storage + base) of each copied variable, in case we need to restore the storage + as the same (valid) variables layout as in original one. + + Variables with valid format and following state can be taken as valid: + - with state VAR_ADDED; + - with state VAR_IN_DELETED_TRANSITION but without the same variable + with state VAR_ADDED; + - with state VAR_ADDED and/or VAR_IN_DELETED_TRANSITION for variable + MetaDataHmacVar. + + @param[out] StoreCacheBase Base address of variable storage cache. + @param[in,out] StoreCacheSize Size of space in StoreCacheBase. + @param[out] IndexTable Buffer of index (offset) table with entries of + VariableNumber. + @param[out] VariableNumber Number of valid variables. + @param[out] AuthFlag Aut-variable indicator. + + @return EFI_INVALID_PARAMETER Invalid StoreCacheSize and/or StoreCacheBase. + @return EFI_VOLUME_CORRUPTED Invalid or no NV variable storage found. + @return EFI_BUFFER_TOO_SMALL StoreCacheSize is smaller than needed. + @return EFI_SUCCESS NV variable storage is cached successfully. +**/ +EFI_STATUS +EFIAPI +InitNvVariableStore ( + OUT EFI_PHYSICAL_ADDRESS StoreCacheBase OPTIONAL, + IN OUT UINT32 *StoreCacheSize, + OUT UINT32 *IndexTable OPTIONAL, + OUT UINT32 *VariableNumber OPTIONAL, + OUT BOOLEAN *AuthFlag OPTIONAL + ); + +#endif diff --git a/MdeModulePkg/Universal/Variable/Pei/Variable.c b/MdeModulePkg/Universal/Variable/Pei/Variable.c index 26a4c73b45a5..ce790946626e 100644 --- a/MdeModulePkg/Universal/Variable/Pei/Variable.c +++ b/MdeModulePkg/Universal/Variable/Pei/Variable.c @@ -2,20 +2,22 @@ Implement ReadOnly Variable Services required by PEIM and install PEI ReadOnly Varaiable2 PPI. These services operates the non volatile storage space. -Copyright (c) 2006 - 2019, Intel Corporation. All rights reserved.
+Copyright (c) 2006 - 2022, Intel Corporation. All rights reserved.
Copyright (c) Microsoft Corporation.
SPDX-License-Identifier: BSD-2-Clause-Patent **/ #include "Variable.h" +#include "VariableParsing.h" +#include "VariableStore.h" // // Module globals // EFI_PEI_READ_ONLY_VARIABLE2_PPI mVariablePpi = { - PeiGetVariable, - PeiGetNextVariableName + PeiGetVariableEx, + PeiGetNextVariableNameEx }; EFI_PEI_PPI_DESCRIPTOR mPpiListVariable = { @@ -41,763 +43,33 @@ PeimInitializeVariableServices ( IN CONST EFI_PEI_SERVICES **PeiServices ) { + EFI_STATUS Status; + PROTECTED_VARIABLE_CONTEXT_IN ContextIn; + + // + // If protected variable services are not supported, EFI_UNSUPPORTED should + // be always returned. Check it here. + // + ContextIn.StructVersion = PROTECTED_VARIABLE_CONTEXT_IN_STRUCT_VERSION; + ContextIn.StructSize = sizeof (ContextIn); + + ContextIn.MaxVariableSize = 0; + ContextIn.VariableServiceUser = FromPeiModule; + ContextIn.GetVariableInfo = GetVariableInfo; + ContextIn.GetNextVariableInfo = GetNextVariableInfo; + ContextIn.FindVariableSmm = NULL; + ContextIn.UpdateVariableStore = NULL; + ContextIn.UpdateVariable = NULL; + ContextIn.IsHobVariableStoreAvailable = IsHobVariableStoreAvailable; + + Status = ProtectedVariableLibInitialize (&ContextIn); + if (EFI_ERROR (Status) && (Status != EFI_UNSUPPORTED)) { + return Status; + } + return PeiServicesInstallPpi (&mPpiListVariable); } -/** - - Gets the pointer to the first variable header in given variable store area. - - @param VarStoreHeader Pointer to the Variable Store Header. - - @return Pointer to the first variable header. - -**/ -VARIABLE_HEADER * -GetStartPointer ( - IN VARIABLE_STORE_HEADER *VarStoreHeader - ) -{ - // - // The start of variable store - // - return (VARIABLE_HEADER *)HEADER_ALIGN (VarStoreHeader + 1); -} - -/** - - Gets the pointer to the end of the variable storage area. - - This function gets pointer to the end of the variable storage - area, according to the input variable store header. - - @param VarStoreHeader Pointer to the Variable Store Header. - - @return Pointer to the end of the variable storage area. - -**/ -VARIABLE_HEADER * -GetEndPointer ( - IN VARIABLE_STORE_HEADER *VarStoreHeader - ) -{ - // - // The end of variable store - // - return (VARIABLE_HEADER *)HEADER_ALIGN ((UINTN)VarStoreHeader + VarStoreHeader->Size); -} - -/** - This code checks if variable header is valid or not. - - @param Variable Pointer to the Variable Header. - - @retval TRUE Variable header is valid. - @retval FALSE Variable header is not valid. - -**/ -BOOLEAN -IsValidVariableHeader ( - IN VARIABLE_HEADER *Variable - ) -{ - if ((Variable == NULL) || (Variable->StartId != VARIABLE_DATA)) { - return FALSE; - } - - return TRUE; -} - -/** - This code gets the size of variable header. - - @param AuthFlag Authenticated variable flag. - - @return Size of variable header in bytes in type UINTN. - -**/ -UINTN -GetVariableHeaderSize ( - IN BOOLEAN AuthFlag - ) -{ - UINTN Value; - - if (AuthFlag) { - Value = sizeof (AUTHENTICATED_VARIABLE_HEADER); - } else { - Value = sizeof (VARIABLE_HEADER); - } - - return Value; -} - -/** - This code gets the size of name of variable. - - @param Variable Pointer to the Variable Header. - @param AuthFlag Authenticated variable flag. - - @return Size of variable in bytes in type UINTN. - -**/ -UINTN -NameSizeOfVariable ( - IN VARIABLE_HEADER *Variable, - IN BOOLEAN AuthFlag - ) -{ - AUTHENTICATED_VARIABLE_HEADER *AuthVariable; - - AuthVariable = (AUTHENTICATED_VARIABLE_HEADER *)Variable; - if (AuthFlag) { - if ((AuthVariable->State == (UINT8)(-1)) || - (AuthVariable->DataSize == (UINT32)(-1)) || - (AuthVariable->NameSize == (UINT32)(-1)) || - (AuthVariable->Attributes == (UINT32)(-1))) - { - return 0; - } - - return (UINTN)AuthVariable->NameSize; - } else { - if ((Variable->State == (UINT8)(-1)) || - (Variable->DataSize == (UINT32)(-1)) || - (Variable->NameSize == (UINT32)(-1)) || - (Variable->Attributes == (UINT32)(-1))) - { - return 0; - } - - return (UINTN)Variable->NameSize; - } -} - -/** - This code gets the size of data of variable. - - @param Variable Pointer to the Variable Header. - @param AuthFlag Authenticated variable flag. - - @return Size of variable in bytes in type UINTN. - -**/ -UINTN -DataSizeOfVariable ( - IN VARIABLE_HEADER *Variable, - IN BOOLEAN AuthFlag - ) -{ - AUTHENTICATED_VARIABLE_HEADER *AuthVariable; - - AuthVariable = (AUTHENTICATED_VARIABLE_HEADER *)Variable; - if (AuthFlag) { - if ((AuthVariable->State == (UINT8)(-1)) || - (AuthVariable->DataSize == (UINT32)(-1)) || - (AuthVariable->NameSize == (UINT32)(-1)) || - (AuthVariable->Attributes == (UINT32)(-1))) - { - return 0; - } - - return (UINTN)AuthVariable->DataSize; - } else { - if ((Variable->State == (UINT8)(-1)) || - (Variable->DataSize == (UINT32)(-1)) || - (Variable->NameSize == (UINT32)(-1)) || - (Variable->Attributes == (UINT32)(-1))) - { - return 0; - } - - return (UINTN)Variable->DataSize; - } -} - -/** - This code gets the pointer to the variable name. - - @param Variable Pointer to the Variable Header. - @param AuthFlag Authenticated variable flag. - - @return A CHAR16* pointer to Variable Name. - -**/ -CHAR16 * -GetVariableNamePtr ( - IN VARIABLE_HEADER *Variable, - IN BOOLEAN AuthFlag - ) -{ - return (CHAR16 *)((UINTN)Variable + GetVariableHeaderSize (AuthFlag)); -} - -/** - This code gets the pointer to the variable guid. - - @param Variable Pointer to the Variable Header. - @param AuthFlag Authenticated variable flag. - - @return A EFI_GUID* pointer to Vendor Guid. - -**/ -EFI_GUID * -GetVendorGuidPtr ( - IN VARIABLE_HEADER *Variable, - IN BOOLEAN AuthFlag - ) -{ - AUTHENTICATED_VARIABLE_HEADER *AuthVariable; - - AuthVariable = (AUTHENTICATED_VARIABLE_HEADER *)Variable; - if (AuthFlag) { - return &AuthVariable->VendorGuid; - } else { - return &Variable->VendorGuid; - } -} - -/** - This code gets the pointer to the variable data. - - @param Variable Pointer to the Variable Header. - @param VariableHeader Pointer to the Variable Header that has consecutive content. - @param AuthFlag Authenticated variable flag. - - @return A UINT8* pointer to Variable Data. - -**/ -UINT8 * -GetVariableDataPtr ( - IN VARIABLE_HEADER *Variable, - IN VARIABLE_HEADER *VariableHeader, - IN BOOLEAN AuthFlag - ) -{ - UINTN Value; - - // - // Be careful about pad size for alignment - // - Value = (UINTN)GetVariableNamePtr (Variable, AuthFlag); - Value += NameSizeOfVariable (VariableHeader, AuthFlag); - Value += GET_PAD_SIZE (NameSizeOfVariable (VariableHeader, AuthFlag)); - - return (UINT8 *)Value; -} - -/** - This code gets the pointer to the next variable header. - - @param StoreInfo Pointer to variable store info structure. - @param Variable Pointer to the Variable Header. - @param VariableHeader Pointer to the Variable Header that has consecutive content. - - @return A VARIABLE_HEADER* pointer to next variable header. - -**/ -VARIABLE_HEADER * -GetNextVariablePtr ( - IN VARIABLE_STORE_INFO *StoreInfo, - IN VARIABLE_HEADER *Variable, - IN VARIABLE_HEADER *VariableHeader - ) -{ - EFI_PHYSICAL_ADDRESS TargetAddress; - EFI_PHYSICAL_ADDRESS SpareAddress; - UINTN Value; - - Value = (UINTN)GetVariableDataPtr (Variable, VariableHeader, StoreInfo->AuthFlag); - Value += DataSizeOfVariable (VariableHeader, StoreInfo->AuthFlag); - Value += GET_PAD_SIZE (DataSizeOfVariable (VariableHeader, StoreInfo->AuthFlag)); - // - // Be careful about pad size for alignment - // - Value = HEADER_ALIGN (Value); - - if (StoreInfo->FtwLastWriteData != NULL) { - TargetAddress = StoreInfo->FtwLastWriteData->TargetAddress; - SpareAddress = StoreInfo->FtwLastWriteData->SpareAddress; - if (((UINTN)Variable < (UINTN)TargetAddress) && (Value >= (UINTN)TargetAddress)) { - // - // Next variable is in spare block. - // - Value = (UINTN)SpareAddress + (Value - (UINTN)TargetAddress); - } - } - - return (VARIABLE_HEADER *)Value; -} - -/** - Get variable store status. - - @param VarStoreHeader Pointer to the Variable Store Header. - - @retval EfiRaw Variable store is raw - @retval EfiValid Variable store is valid - @retval EfiInvalid Variable store is invalid - -**/ -VARIABLE_STORE_STATUS -GetVariableStoreStatus ( - IN VARIABLE_STORE_HEADER *VarStoreHeader - ) -{ - if ((CompareGuid (&VarStoreHeader->Signature, &gEfiAuthenticatedVariableGuid) || - CompareGuid (&VarStoreHeader->Signature, &gEfiVariableGuid)) && - (VarStoreHeader->Format == VARIABLE_STORE_FORMATTED) && - (VarStoreHeader->State == VARIABLE_STORE_HEALTHY) - ) - { - return EfiValid; - } - - if ((((UINT32 *)(&VarStoreHeader->Signature))[0] == 0xffffffff) && - (((UINT32 *)(&VarStoreHeader->Signature))[1] == 0xffffffff) && - (((UINT32 *)(&VarStoreHeader->Signature))[2] == 0xffffffff) && - (((UINT32 *)(&VarStoreHeader->Signature))[3] == 0xffffffff) && - (VarStoreHeader->Size == 0xffffffff) && - (VarStoreHeader->Format == 0xff) && - (VarStoreHeader->State == 0xff) - ) - { - return EfiRaw; - } else { - return EfiInvalid; - } -} - -/** - Compare two variable names, one of them may be inconsecutive. - - @param StoreInfo Pointer to variable store info structure. - @param Name1 Pointer to one variable name. - @param Name2 Pointer to another variable name. - @param NameSize Variable name size. - - @retval TRUE Name1 and Name2 are identical. - @retval FALSE Name1 and Name2 are not identical. - -**/ -BOOLEAN -CompareVariableName ( - IN VARIABLE_STORE_INFO *StoreInfo, - IN CONST CHAR16 *Name1, - IN CONST CHAR16 *Name2, - IN UINTN NameSize - ) -{ - EFI_PHYSICAL_ADDRESS TargetAddress; - EFI_PHYSICAL_ADDRESS SpareAddress; - UINTN PartialNameSize; - - if (StoreInfo->FtwLastWriteData != NULL) { - TargetAddress = StoreInfo->FtwLastWriteData->TargetAddress; - SpareAddress = StoreInfo->FtwLastWriteData->SpareAddress; - if (((UINTN)Name1 < (UINTN)TargetAddress) && (((UINTN)Name1 + NameSize) > (UINTN)TargetAddress)) { - // - // Name1 is inconsecutive. - // - PartialNameSize = (UINTN)TargetAddress - (UINTN)Name1; - // - // Partial content is in NV storage. - // - if (CompareMem ((UINT8 *)Name1, (UINT8 *)Name2, PartialNameSize) == 0) { - // - // Another partial content is in spare block. - // - if (CompareMem ((UINT8 *)(UINTN)SpareAddress, (UINT8 *)Name2 + PartialNameSize, NameSize - PartialNameSize) == 0) { - return TRUE; - } - } - - return FALSE; - } else if (((UINTN)Name2 < (UINTN)TargetAddress) && (((UINTN)Name2 + NameSize) > (UINTN)TargetAddress)) { - // - // Name2 is inconsecutive. - // - PartialNameSize = (UINTN)TargetAddress - (UINTN)Name2; - // - // Partial content is in NV storage. - // - if (CompareMem ((UINT8 *)Name2, (UINT8 *)Name1, PartialNameSize) == 0) { - // - // Another partial content is in spare block. - // - if (CompareMem ((UINT8 *)(UINTN)SpareAddress, (UINT8 *)Name1 + PartialNameSize, NameSize - PartialNameSize) == 0) { - return TRUE; - } - } - - return FALSE; - } - } - - // - // Both Name1 and Name2 are consecutive. - // - if (CompareMem ((UINT8 *)Name1, (UINT8 *)Name2, NameSize) == 0) { - return TRUE; - } - - return FALSE; -} - -/** - This function compares a variable with variable entries in database. - - @param StoreInfo Pointer to variable store info structure. - @param Variable Pointer to the variable in our database - @param VariableHeader Pointer to the Variable Header that has consecutive content. - @param VariableName Name of the variable to compare to 'Variable' - @param VendorGuid GUID of the variable to compare to 'Variable' - @param PtrTrack Variable Track Pointer structure that contains Variable Information. - - @retval EFI_SUCCESS Found match variable - @retval EFI_NOT_FOUND Variable not found - -**/ -EFI_STATUS -CompareWithValidVariable ( - IN VARIABLE_STORE_INFO *StoreInfo, - IN VARIABLE_HEADER *Variable, - IN VARIABLE_HEADER *VariableHeader, - IN CONST CHAR16 *VariableName, - IN CONST EFI_GUID *VendorGuid, - OUT VARIABLE_POINTER_TRACK *PtrTrack - ) -{ - VOID *Point; - EFI_GUID *TempVendorGuid; - - TempVendorGuid = GetVendorGuidPtr (VariableHeader, StoreInfo->AuthFlag); - - if (VariableName[0] == 0) { - PtrTrack->CurrPtr = Variable; - return EFI_SUCCESS; - } else { - // - // Don't use CompareGuid function here for performance reasons. - // Instead we compare the GUID a UINT32 at a time and branch - // on the first failed comparison. - // - if ((((INT32 *)VendorGuid)[0] == ((INT32 *)TempVendorGuid)[0]) && - (((INT32 *)VendorGuid)[1] == ((INT32 *)TempVendorGuid)[1]) && - (((INT32 *)VendorGuid)[2] == ((INT32 *)TempVendorGuid)[2]) && - (((INT32 *)VendorGuid)[3] == ((INT32 *)TempVendorGuid)[3]) - ) - { - ASSERT (NameSizeOfVariable (VariableHeader, StoreInfo->AuthFlag) != 0); - Point = (VOID *)GetVariableNamePtr (Variable, StoreInfo->AuthFlag); - if (CompareVariableName (StoreInfo, VariableName, Point, NameSizeOfVariable (VariableHeader, StoreInfo->AuthFlag))) { - PtrTrack->CurrPtr = Variable; - return EFI_SUCCESS; - } - } - } - - return EFI_NOT_FOUND; -} - -/** - Get HOB variable store. - - @param[out] StoreInfo Return the store info. - @param[out] VariableStoreHeader Return variable store header. - -**/ -VOID -GetHobVariableStore ( - OUT VARIABLE_STORE_INFO *StoreInfo, - OUT VARIABLE_STORE_HEADER **VariableStoreHeader - ) -{ - EFI_HOB_GUID_TYPE *GuidHob; - - // - // Make sure there is no more than one Variable HOB. - // - DEBUG_CODE_BEGIN (); - GuidHob = GetFirstGuidHob (&gEfiAuthenticatedVariableGuid); - if (GuidHob != NULL) { - if ((GetNextGuidHob (&gEfiAuthenticatedVariableGuid, GET_NEXT_HOB (GuidHob)) != NULL)) { - DEBUG ((DEBUG_ERROR, "ERROR: Found two Auth Variable HOBs\n")); - ASSERT (FALSE); - } else if (GetFirstGuidHob (&gEfiVariableGuid) != NULL) { - DEBUG ((DEBUG_ERROR, "ERROR: Found one Auth + one Normal Variable HOBs\n")); - ASSERT (FALSE); - } - } else { - GuidHob = GetFirstGuidHob (&gEfiVariableGuid); - if (GuidHob != NULL) { - if ((GetNextGuidHob (&gEfiVariableGuid, GET_NEXT_HOB (GuidHob)) != NULL)) { - DEBUG ((DEBUG_ERROR, "ERROR: Found two Normal Variable HOBs\n")); - ASSERT (FALSE); - } - } - } - - DEBUG_CODE_END (); - - GuidHob = GetFirstGuidHob (&gEfiAuthenticatedVariableGuid); - if (GuidHob != NULL) { - *VariableStoreHeader = (VARIABLE_STORE_HEADER *)GET_GUID_HOB_DATA (GuidHob); - StoreInfo->AuthFlag = TRUE; - } else { - GuidHob = GetFirstGuidHob (&gEfiVariableGuid); - if (GuidHob != NULL) { - *VariableStoreHeader = (VARIABLE_STORE_HEADER *)GET_GUID_HOB_DATA (GuidHob); - StoreInfo->AuthFlag = FALSE; - } - } -} - -/** - Return the variable store header and the store info based on the Index. - - @param Type The type of the variable store. - @param StoreInfo Return the store info. - - @return Pointer to the variable store header. -**/ -VARIABLE_STORE_HEADER * -GetVariableStore ( - IN VARIABLE_STORE_TYPE Type, - OUT VARIABLE_STORE_INFO *StoreInfo - ) -{ - EFI_STATUS Status; - EFI_HOB_GUID_TYPE *GuidHob; - EFI_FIRMWARE_VOLUME_HEADER *FvHeader; - VARIABLE_STORE_HEADER *VariableStoreHeader; - EFI_PHYSICAL_ADDRESS NvStorageBase; - UINT32 NvStorageSize; - UINT64 NvStorageSize64; - FAULT_TOLERANT_WRITE_LAST_WRITE_DATA *FtwLastWriteData; - UINT32 BackUpOffset; - - StoreInfo->IndexTable = NULL; - StoreInfo->FtwLastWriteData = NULL; - StoreInfo->AuthFlag = FALSE; - VariableStoreHeader = NULL; - switch (Type) { - case VariableStoreTypeHob: - GetHobVariableStore (StoreInfo, &VariableStoreHeader); - - break; - - case VariableStoreTypeNv: - if (!PcdGetBool (PcdEmuVariableNvModeEnable)) { - // - // Emulated non-volatile variable mode is not enabled. - // - - Status = GetVariableFlashNvStorageInfo (&NvStorageBase, &NvStorageSize64); - ASSERT_EFI_ERROR (Status); - - Status = SafeUint64ToUint32 (NvStorageSize64, &NvStorageSize); - // This driver currently assumes the size will be UINT32 so assert the value is safe for now. - ASSERT_EFI_ERROR (Status); - - ASSERT (NvStorageBase != 0); - - // - // First let FvHeader point to NV storage base. - // - FvHeader = (EFI_FIRMWARE_VOLUME_HEADER *)(UINTN)NvStorageBase; - - // - // Check the FTW last write data hob. - // - BackUpOffset = 0; - GuidHob = GetFirstGuidHob (&gEdkiiFaultTolerantWriteGuid); - if (GuidHob != NULL) { - FtwLastWriteData = (FAULT_TOLERANT_WRITE_LAST_WRITE_DATA *)GET_GUID_HOB_DATA (GuidHob); - if (FtwLastWriteData->TargetAddress == NvStorageBase) { - // - // Let FvHeader point to spare block. - // - FvHeader = (EFI_FIRMWARE_VOLUME_HEADER *)(UINTN)FtwLastWriteData->SpareAddress; - DEBUG ((DEBUG_INFO, "PeiVariable: NV storage is backed up in spare block: 0x%x\n", (UINTN)FtwLastWriteData->SpareAddress)); - } else if ((FtwLastWriteData->TargetAddress > NvStorageBase) && (FtwLastWriteData->TargetAddress < (NvStorageBase + NvStorageSize))) { - StoreInfo->FtwLastWriteData = FtwLastWriteData; - // - // Flash NV storage from the offset is backed up in spare block. - // - BackUpOffset = (UINT32)(FtwLastWriteData->TargetAddress - NvStorageBase); - DEBUG ((DEBUG_INFO, "PeiVariable: High partial NV storage from offset: %x is backed up in spare block: 0x%x\n", BackUpOffset, (UINTN)FtwLastWriteData->SpareAddress)); - // - // At least one block data in flash NV storage is still valid, so still leave FvHeader point to NV storage base. - // - } - } - - // - // Check if the Firmware Volume is not corrupted - // - if ((FvHeader->Signature != EFI_FVH_SIGNATURE) || (!CompareGuid (&gEfiSystemNvDataFvGuid, &FvHeader->FileSystemGuid))) { - DEBUG ((DEBUG_ERROR, "Firmware Volume for Variable Store is corrupted\n")); - break; - } - - VariableStoreHeader = (VARIABLE_STORE_HEADER *)((UINT8 *)FvHeader + FvHeader->HeaderLength); - - StoreInfo->AuthFlag = (BOOLEAN)(CompareGuid (&VariableStoreHeader->Signature, &gEfiAuthenticatedVariableGuid)); - - GuidHob = GetFirstGuidHob (&gEfiVariableIndexTableGuid); - if (GuidHob != NULL) { - StoreInfo->IndexTable = GET_GUID_HOB_DATA (GuidHob); - } else { - // - // If it's the first time to access variable region in flash, create a guid hob to record - // VAR_ADDED type variable info. - // Note that as the resource of PEI phase is limited, only store the limited number of - // VAR_ADDED type variables to reduce access time. - // - StoreInfo->IndexTable = (VARIABLE_INDEX_TABLE *)BuildGuidHob (&gEfiVariableIndexTableGuid, sizeof (VARIABLE_INDEX_TABLE)); - StoreInfo->IndexTable->Length = 0; - StoreInfo->IndexTable->StartPtr = GetStartPointer (VariableStoreHeader); - StoreInfo->IndexTable->EndPtr = GetEndPointer (VariableStoreHeader); - StoreInfo->IndexTable->GoneThrough = 0; - } - } - - break; - - default: - ASSERT (FALSE); - break; - } - - StoreInfo->VariableStoreHeader = VariableStoreHeader; - return VariableStoreHeader; -} - -/** - Get variable header that has consecutive content. - - @param StoreInfo Pointer to variable store info structure. - @param Variable Pointer to the Variable Header. - @param VariableHeader Pointer to Pointer to the Variable Header that has consecutive content. - - @retval TRUE Variable header is valid. - @retval FALSE Variable header is not valid. - -**/ -BOOLEAN -GetVariableHeader ( - IN VARIABLE_STORE_INFO *StoreInfo, - IN VARIABLE_HEADER *Variable, - OUT VARIABLE_HEADER **VariableHeader - ) -{ - EFI_PHYSICAL_ADDRESS TargetAddress; - EFI_PHYSICAL_ADDRESS SpareAddress; - EFI_HOB_GUID_TYPE *GuidHob; - UINTN PartialHeaderSize; - - if (Variable == NULL) { - return FALSE; - } - - // - // First assume variable header pointed by Variable is consecutive. - // - *VariableHeader = Variable; - - if (StoreInfo->FtwLastWriteData != NULL) { - TargetAddress = StoreInfo->FtwLastWriteData->TargetAddress; - SpareAddress = StoreInfo->FtwLastWriteData->SpareAddress; - if (((UINTN)Variable > (UINTN)SpareAddress) && - (((UINTN)Variable - (UINTN)SpareAddress + (UINTN)TargetAddress) >= (UINTN)GetEndPointer (StoreInfo->VariableStoreHeader))) - { - // - // Reach the end of variable store. - // - return FALSE; - } - - if (((UINTN)Variable < (UINTN)TargetAddress) && (((UINTN)Variable + GetVariableHeaderSize (StoreInfo->AuthFlag)) > (UINTN)TargetAddress)) { - // - // Variable header pointed by Variable is inconsecutive, - // create a guid hob to combine the two partial variable header content together. - // - GuidHob = GetFirstGuidHob (&gEfiCallerIdGuid); - if (GuidHob != NULL) { - *VariableHeader = (VARIABLE_HEADER *)GET_GUID_HOB_DATA (GuidHob); - } else { - *VariableHeader = (VARIABLE_HEADER *)BuildGuidHob (&gEfiCallerIdGuid, GetVariableHeaderSize (StoreInfo->AuthFlag)); - PartialHeaderSize = (UINTN)TargetAddress - (UINTN)Variable; - // - // Partial content is in NV storage. - // - CopyMem ((UINT8 *)*VariableHeader, (UINT8 *)Variable, PartialHeaderSize); - // - // Another partial content is in spare block. - // - CopyMem ((UINT8 *)*VariableHeader + PartialHeaderSize, (UINT8 *)(UINTN)SpareAddress, GetVariableHeaderSize (StoreInfo->AuthFlag) - PartialHeaderSize); - } - } - } else { - if (Variable >= GetEndPointer (StoreInfo->VariableStoreHeader)) { - // - // Reach the end of variable store. - // - return FALSE; - } - } - - return IsValidVariableHeader (*VariableHeader); -} - -/** - Get variable name or data to output buffer. - - @param StoreInfo Pointer to variable store info structure. - @param NameOrData Pointer to the variable name/data that may be inconsecutive. - @param Size Variable name/data size. - @param Buffer Pointer to output buffer to hold the variable name/data. - -**/ -VOID -GetVariableNameOrData ( - IN VARIABLE_STORE_INFO *StoreInfo, - IN UINT8 *NameOrData, - IN UINTN Size, - OUT UINT8 *Buffer - ) -{ - EFI_PHYSICAL_ADDRESS TargetAddress; - EFI_PHYSICAL_ADDRESS SpareAddress; - UINTN PartialSize; - - if (StoreInfo->FtwLastWriteData != NULL) { - TargetAddress = StoreInfo->FtwLastWriteData->TargetAddress; - SpareAddress = StoreInfo->FtwLastWriteData->SpareAddress; - if (((UINTN)NameOrData < (UINTN)TargetAddress) && (((UINTN)NameOrData + Size) > (UINTN)TargetAddress)) { - // - // Variable name/data is inconsecutive. - // - PartialSize = (UINTN)TargetAddress - (UINTN)NameOrData; - // - // Partial content is in NV storage. - // - CopyMem (Buffer, NameOrData, PartialSize); - // - // Another partial content is in spare block. - // - CopyMem (Buffer + PartialSize, (UINT8 *)(UINTN)SpareAddress, Size - PartialSize); - return; - } - } - - // - // Variable name/data is consecutive. - // - CopyMem (Buffer, NameOrData, Size); -} - /** Find the variable in the specified variable store. @@ -1250,3 +522,107 @@ PeiGetNextVariableName ( } } } + +/** + This service retrieves a variable's value using its name and GUID. + + Read the specified variable from the UEFI variable store. If the Data + buffer is too small to hold the contents of the variable, the error + EFI_BUFFER_TOO_SMALL is returned and DataSize is set to the required buffer + size to obtain the data. + + @param This A pointer to this instance of the EFI_PEI_READ_ONLY_VARIABLE2_PPI. + @param VariableName A pointer to a null-terminated string that is the variable's name. + @param VariableGuid A pointer to an EFI_GUID that is the variable's GUID. The combination of + VariableGuid and VariableName must be unique. + @param Attributes If non-NULL, on return, points to the variable's attributes. + @param DataSize On entry, points to the size in bytes of the Data buffer. + On return, points to the size of the data returned in Data. + @param Data Points to the buffer which will hold the returned variable value. + May be NULL with a zero DataSize in order to determine the size of the buffer needed. + + @retval EFI_SUCCESS The variable was read successfully. + @retval EFI_NOT_FOUND The variable was be found. + @retval EFI_BUFFER_TOO_SMALL The DataSize is too small for the resulting data. + DataSize is updated with the size required for + the specified variable. + @retval EFI_INVALID_PARAMETER VariableName, VariableGuid, DataSize or Data is NULL. + @retval EFI_DEVICE_ERROR The variable could not be retrieved because of a device error. + +**/ +EFI_STATUS +EFIAPI +PeiGetVariableEx ( + IN CONST EFI_PEI_READ_ONLY_VARIABLE2_PPI *This, + IN CONST CHAR16 *VariableName, + IN CONST EFI_GUID *VariableGuid, + OUT UINT32 *Attributes, + IN OUT UINTN *DataSize, + OUT VOID *Data OPTIONAL + ) +{ + EFI_STATUS Status; + + // + // If variable protection is employed, always get variable data through + // ProtectedVariableLib. + // + Status = ProtectedVariableLibGetByName (VariableName, VariableGuid, Attributes, DataSize, Data); + if (Status != EFI_UNSUPPORTED) { + return Status; + } + + return PeiGetVariable (This, VariableName, VariableGuid, Attributes, DataSize, Data); +} + +/** + Return the next variable name and GUID. + + This function is called multiple times to retrieve the VariableName + and VariableGuid of all variables currently available in the system. + On each call, the previous results are passed into the interface, + and, on return, the interface returns the data for the next + interface. When the entire variable list has been returned, + EFI_NOT_FOUND is returned. + + @param This A pointer to this instance of the EFI_PEI_READ_ONLY_VARIABLE2_PPI. + + @param VariableNameSize On entry, points to the size of the buffer pointed to by VariableName. + On return, the size of the variable name buffer. + @param VariableName On entry, a pointer to a null-terminated string that is the variable's name. + On return, points to the next variable's null-terminated name string. + @param VariableGuid On entry, a pointer to an EFI_GUID that is the variable's GUID. + On return, a pointer to the next variable's GUID. + + @retval EFI_SUCCESS The variable was read successfully. + @retval EFI_NOT_FOUND The variable could not be found. + @retval EFI_BUFFER_TOO_SMALL The VariableNameSize is too small for the resulting + data. VariableNameSize is updated with the size + required for the specified variable. + @retval EFI_INVALID_PARAMETER VariableName, VariableGuid or + VariableNameSize is NULL. + @retval EFI_DEVICE_ERROR The variable could not be retrieved because of a device error. + +**/ +EFI_STATUS +EFIAPI +PeiGetNextVariableNameEx ( + IN CONST EFI_PEI_READ_ONLY_VARIABLE2_PPI *This, + IN OUT UINTN *VariableNameSize, + IN OUT CHAR16 *VariableName, + IN OUT EFI_GUID *VariableGuid + ) +{ + EFI_STATUS Status; + + // + // If variable protection is employed, always get next variable through + // ProtectedVariableLib. + // + Status = ProtectedVariableLibFindNext (VariableNameSize, VariableName, VariableGuid); + if (Status != EFI_UNSUPPORTED) { + return Status; + } + + return PeiGetNextVariableName (This, VariableNameSize, VariableName, VariableGuid); +} diff --git a/MdeModulePkg/Universal/Variable/Pei/VariableParsing.c b/MdeModulePkg/Universal/Variable/Pei/VariableParsing.c new file mode 100644 index 000000000000..2d605d39cbb6 --- /dev/null +++ b/MdeModulePkg/Universal/Variable/Pei/VariableParsing.c @@ -0,0 +1,941 @@ +/** @file + Implement ReadOnly Variable Services required by PEIM and install + PEI ReadOnly Varaiable2 PPI. These services operates the non volatile storage space. + +Copyright (c) 2022, Intel Corporation. All rights reserved.
+SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "Variable.h" +#include "VariableStore.h" + +/** + + Gets the pointer to the first variable header in given variable store area. + + @param[in] VarStoreHeader Pointer to the Variable Store Header. + + @return Pointer to the first variable header. + +**/ +VARIABLE_HEADER * +GetStartPointer ( + IN VARIABLE_STORE_HEADER *VarStoreHeader + ) +{ + // + // The start of variable store + // + return (VARIABLE_HEADER *)HEADER_ALIGN (VarStoreHeader + 1); +} + +/** + + Gets the pointer to the end of the variable storage area. + + This function gets pointer to the end of the variable storage + area, according to the input variable store header. + + @param[in] VarStoreHeader Pointer to the Variable Store Header. + + @return Pointer to the end of the variable storage area. + +**/ +VARIABLE_HEADER * +GetEndPointer ( + IN VARIABLE_STORE_HEADER *VarStoreHeader + ) +{ + // + // The end of variable store + // + return (VARIABLE_HEADER *)HEADER_ALIGN ((UINTN)VarStoreHeader + VarStoreHeader->Size); +} + +/** + This code checks if variable header is valid or not. + + @param[in] Variable Pointer to the Variable Header. + + @retval TRUE Variable header is valid. + @retval FALSE Variable header is not valid. + +**/ +BOOLEAN +IsValidVariableHeader ( + IN VARIABLE_HEADER *Variable + ) +{ + if ((Variable == NULL) || (Variable->StartId != VARIABLE_DATA)) { + return FALSE; + } + + return TRUE; +} + +/** + This code gets the size of variable header. + + @param[in] AuthFlag Authenticated variable flag. + + @return Size of variable header in bytes in type UINTN. + +**/ +UINTN +GetVariableHeaderSize ( + IN BOOLEAN AuthFlag + ) +{ + UINTN Value; + + if (AuthFlag) { + Value = sizeof (AUTHENTICATED_VARIABLE_HEADER); + } else { + Value = sizeof (VARIABLE_HEADER); + } + + return Value; +} + +/** + This code gets the size of name of variable. + + @param[in] Variable Pointer to the Variable Header. + @param[in] AuthFlag Authenticated variable flag. + + @return Size of variable in bytes in type UINTN. + +**/ +UINTN +NameSizeOfVariable ( + IN VARIABLE_HEADER *Variable, + IN BOOLEAN AuthFlag + ) +{ + AUTHENTICATED_VARIABLE_HEADER *AuthVariable; + + AuthVariable = (AUTHENTICATED_VARIABLE_HEADER *)Variable; + if (AuthFlag) { + if ((AuthVariable->State == (UINT8)(-1)) || + (AuthVariable->DataSize == (UINT32)(-1)) || + (AuthVariable->NameSize == (UINT32)(-1)) || + (AuthVariable->Attributes == (UINT32)(-1))) + { + return 0; + } + + return (UINTN)AuthVariable->NameSize; + } else { + if ((Variable->State == (UINT8)(-1)) || + (Variable->DataSize == (UINT32)(-1)) || + (Variable->NameSize == (UINT32)(-1)) || + (Variable->Attributes == (UINT32)(-1))) + { + return 0; + } + + return (UINTN)Variable->NameSize; + } +} + +/** + This code gets the size of data of variable. + + @param[in] Variable Pointer to the Variable Header. + @param[in] AuthFlag Authenticated variable flag. + + @return Size of variable in bytes in type UINTN. + +**/ +UINTN +DataSizeOfVariable ( + IN VARIABLE_HEADER *Variable, + IN BOOLEAN AuthFlag + ) +{ + AUTHENTICATED_VARIABLE_HEADER *AuthVariable; + + AuthVariable = (AUTHENTICATED_VARIABLE_HEADER *)Variable; + if (AuthFlag) { + if ((AuthVariable->State == (UINT8)(-1)) || + (AuthVariable->DataSize == (UINT32)(-1)) || + (AuthVariable->NameSize == (UINT32)(-1)) || + (AuthVariable->Attributes == (UINT32)(-1))) + { + return 0; + } + + return (UINTN)AuthVariable->DataSize; + } else { + if ((Variable->State == (UINT8)(-1)) || + (Variable->DataSize == (UINT32)(-1)) || + (Variable->NameSize == (UINT32)(-1)) || + (Variable->Attributes == (UINT32)(-1))) + { + return 0; + } + + return (UINTN)Variable->DataSize; + } +} + +/** + This code gets the pointer to the variable name. + + @param[in] Variable Pointer to the Variable Header. + @param[in] AuthFlag Authenticated variable flag. + + @return A CHAR16* pointer to Variable Name. + +**/ +CHAR16 * +GetVariableNamePtr ( + IN VARIABLE_HEADER *Variable, + IN BOOLEAN AuthFlag + ) +{ + return (CHAR16 *)((UINTN)Variable + GetVariableHeaderSize (AuthFlag)); +} + +/** + This code gets the pointer to the variable guid. + + @param[in] Variable Pointer to the Variable Header. + @param[in] AuthFlag Authenticated variable flag. + + @return A EFI_GUID* pointer to Vendor Guid. + +**/ +EFI_GUID * +GetVendorGuidPtr ( + IN VARIABLE_HEADER *Variable, + IN BOOLEAN AuthFlag + ) +{ + AUTHENTICATED_VARIABLE_HEADER *AuthVariable; + + AuthVariable = (AUTHENTICATED_VARIABLE_HEADER *)Variable; + if (AuthFlag) { + return &AuthVariable->VendorGuid; + } else { + return &Variable->VendorGuid; + } +} + +/** + This code gets the pointer to the variable data. + + @param[in] Variable Pointer to the Variable Header. + @param[in] VariableHeader Pointer to the Variable Header that has consecutive content. + @param[in] AuthFlag Authenticated variable flag. + + @return A UINT8* pointer to Variable Data. + +**/ +UINT8 * +GetVariableDataPtr ( + IN VARIABLE_HEADER *Variable, + IN VARIABLE_HEADER *VariableHeader, + IN BOOLEAN AuthFlag + ) +{ + UINTN Value; + + // + // Be careful about pad size for alignment + // + Value = (UINTN)GetVariableNamePtr (Variable, AuthFlag); + Value += NameSizeOfVariable (VariableHeader, AuthFlag); + Value += GET_PAD_SIZE (NameSizeOfVariable (VariableHeader, AuthFlag)); + + return (UINT8 *)Value; +} + +/** + This code gets the pointer to the next variable header. + + @param[in] StoreInfo Pointer to variable store info structure. + @param[in] Variable Pointer to the Variable Header. + @param[in] VariableHeader Pointer to the Variable Header that has consecutive content. + + @return A VARIABLE_HEADER* pointer to next variable header. + +**/ +VARIABLE_HEADER * +GetNextVariablePtr ( + IN VARIABLE_STORE_INFO *StoreInfo, + IN VARIABLE_HEADER *Variable, + IN VARIABLE_HEADER *VariableHeader + ) +{ + EFI_PHYSICAL_ADDRESS TargetAddress; + EFI_PHYSICAL_ADDRESS SpareAddress; + UINTN Value; + + Value = (UINTN)GetVariableDataPtr (Variable, VariableHeader, StoreInfo->AuthFlag); + Value += DataSizeOfVariable (VariableHeader, StoreInfo->AuthFlag); + Value += GET_PAD_SIZE (DataSizeOfVariable (VariableHeader, StoreInfo->AuthFlag)); + // + // Be careful about pad size for alignment + // + Value = HEADER_ALIGN (Value); + + if (StoreInfo->FtwLastWriteData != NULL) { + TargetAddress = StoreInfo->FtwLastWriteData->TargetAddress; + SpareAddress = StoreInfo->FtwLastWriteData->SpareAddress; + if (((UINTN)Variable < (UINTN)TargetAddress) && (Value >= (UINTN)TargetAddress)) { + // + // Next variable is in spare block. + // + Value = (UINTN)SpareAddress + (Value - (UINTN)TargetAddress); + } + } + + return (VARIABLE_HEADER *)Value; +} + +/** + Compare two variable names, one of them may be inconsecutive. + + @param[in] StoreInfo Pointer to variable store info structure. + @param[in] Name1 Pointer to one variable name. + @param[in] Name2 Pointer to another variable name. + @param[in] NameSize Variable name size. + + @retval TRUE Name1 and Name2 are identical. + @retval FALSE Name1 and Name2 are not identical. + +**/ +BOOLEAN +CompareVariableName ( + IN VARIABLE_STORE_INFO *StoreInfo, + IN CONST CHAR16 *Name1, + IN CONST CHAR16 *Name2, + IN UINTN NameSize + ) +{ + EFI_PHYSICAL_ADDRESS TargetAddress; + EFI_PHYSICAL_ADDRESS SpareAddress; + UINTN PartialNameSize; + + if (StoreInfo->FtwLastWriteData != NULL) { + TargetAddress = StoreInfo->FtwLastWriteData->TargetAddress; + SpareAddress = StoreInfo->FtwLastWriteData->SpareAddress; + if (((UINTN)Name1 < (UINTN)TargetAddress) && (((UINTN)Name1 + NameSize) > (UINTN)TargetAddress)) { + // + // Name1 is inconsecutive. + // + PartialNameSize = (UINTN)TargetAddress - (UINTN)Name1; + // + // Partial content is in NV storage. + // + if (CompareMem ((UINT8 *)Name1, (UINT8 *)Name2, PartialNameSize) == 0) { + // + // Another partial content is in spare block. + // + if (CompareMem ((UINT8 *)(UINTN)SpareAddress, (UINT8 *)Name2 + PartialNameSize, NameSize - PartialNameSize) == 0) { + return TRUE; + } + } + + return FALSE; + } else if (((UINTN)Name2 < (UINTN)TargetAddress) && (((UINTN)Name2 + NameSize) > (UINTN)TargetAddress)) { + // + // Name2 is inconsecutive. + // + PartialNameSize = (UINTN)TargetAddress - (UINTN)Name2; + // + // Partial content is in NV storage. + // + if (CompareMem ((UINT8 *)Name2, (UINT8 *)Name1, PartialNameSize) == 0) { + // + // Another partial content is in spare block. + // + if (CompareMem ((UINT8 *)(UINTN)SpareAddress, (UINT8 *)Name1 + PartialNameSize, NameSize - PartialNameSize) == 0) { + return TRUE; + } + } + + return FALSE; + } + } + + // + // Both Name1 and Name2 are consecutive. + // + if (CompareMem ((UINT8 *)Name1, (UINT8 *)Name2, NameSize) == 0) { + return TRUE; + } + + return FALSE; +} + +/** + This function compares a variable with variable entries in database. + + @param[in] StoreInfo Pointer to variable store info structure. + @param[in] Variable Pointer to the variable in our database + @param[in] VariableHeader Pointer to the Variable Header that has + consecutive content. + @param[in] VariableName Name of the variable to compare to 'Variable' + @param[in] VendorGuid GUID of the variable to compare to 'Variable' + @param[out] PtrTrack Variable Track Pointer structure that contains + Variable Information. + + @retval EFI_SUCCESS Found match variable + @retval EFI_NOT_FOUND Variable not found + +**/ +EFI_STATUS +CompareWithValidVariable ( + IN VARIABLE_STORE_INFO *StoreInfo, + IN VARIABLE_HEADER *Variable, + IN VARIABLE_HEADER *VariableHeader, + IN CONST CHAR16 *VariableName, + IN CONST EFI_GUID *VendorGuid, + OUT VARIABLE_POINTER_TRACK *PtrTrack + ) +{ + VOID *Point; + EFI_GUID *TempVendorGuid; + + TempVendorGuid = GetVendorGuidPtr (VariableHeader, StoreInfo->AuthFlag); + + if (VariableName[0] == 0) { + PtrTrack->CurrPtr = Variable; + return EFI_SUCCESS; + } else { + // + // Don't use CompareGuid function here for performance reasons. + // Instead we compare the GUID a UINT32 at a time and branch + // on the first failed comparison. + // + if ((((INT32 *)VendorGuid)[0] == ((INT32 *)TempVendorGuid)[0]) && + (((INT32 *)VendorGuid)[1] == ((INT32 *)TempVendorGuid)[1]) && + (((INT32 *)VendorGuid)[2] == ((INT32 *)TempVendorGuid)[2]) && + (((INT32 *)VendorGuid)[3] == ((INT32 *)TempVendorGuid)[3]) + ) + { + ASSERT (NameSizeOfVariable (VariableHeader, StoreInfo->AuthFlag) != 0); + Point = (VOID *)GetVariableNamePtr (Variable, StoreInfo->AuthFlag); + if (CompareVariableName (StoreInfo, VariableName, Point, NameSizeOfVariable (VariableHeader, StoreInfo->AuthFlag))) { + PtrTrack->CurrPtr = Variable; + return EFI_SUCCESS; + } + } + } + + return EFI_NOT_FOUND; +} + +/** + Get variable header that has consecutive content. + + @param[in] StoreInfo Pointer to variable store info structure. + @param[in] Variable Pointer to the Variable Header. + @param[out] VariableHeader Pointer to Pointer to the Variable Header + that has consecutive content. + + @retval TRUE Variable header is valid. + @retval FALSE Variable header is not valid. + +**/ +BOOLEAN +GetVariableHeader ( + IN VARIABLE_STORE_INFO *StoreInfo, + IN VARIABLE_HEADER *Variable, + OUT VARIABLE_HEADER **VariableHeader + ) +{ + EFI_PHYSICAL_ADDRESS TargetAddress; + EFI_PHYSICAL_ADDRESS SpareAddress; + EFI_HOB_GUID_TYPE *GuidHob; + UINTN PartialHeaderSize; + + if (Variable == NULL) { + return FALSE; + } + + // + // First assume variable header pointed by Variable is consecutive. + // + *VariableHeader = Variable; + + if (StoreInfo->FtwLastWriteData != NULL) { + TargetAddress = StoreInfo->FtwLastWriteData->TargetAddress; + SpareAddress = StoreInfo->FtwLastWriteData->SpareAddress; + if (((UINTN)Variable > (UINTN)SpareAddress) && + (((UINTN)Variable - (UINTN)SpareAddress + (UINTN)TargetAddress) >= (UINTN)GetEndPointer (StoreInfo->VariableStoreHeader))) + { + // + // Reach the end of variable store. + // + return FALSE; + } + + if (((UINTN)Variable < (UINTN)TargetAddress) && (((UINTN)Variable + GetVariableHeaderSize (StoreInfo->AuthFlag)) > (UINTN)TargetAddress)) { + // + // Variable header pointed by Variable is inconsecutive, + // create a guid hob to combine the two partial variable header content together. + // + GuidHob = GetFirstGuidHob (&gEfiCallerIdGuid); + if (GuidHob != NULL) { + *VariableHeader = (VARIABLE_HEADER *)GET_GUID_HOB_DATA (GuidHob); + } else { + *VariableHeader = (VARIABLE_HEADER *)BuildGuidHob (&gEfiCallerIdGuid, GetVariableHeaderSize (StoreInfo->AuthFlag)); + PartialHeaderSize = (UINTN)TargetAddress - (UINTN)Variable; + // + // Partial content is in NV storage. + // + CopyMem ((UINT8 *)*VariableHeader, (UINT8 *)Variable, PartialHeaderSize); + // + // Another partial content is in spare block. + // + CopyMem ((UINT8 *)*VariableHeader + PartialHeaderSize, (UINT8 *)(UINTN)SpareAddress, GetVariableHeaderSize (StoreInfo->AuthFlag) - PartialHeaderSize); + } + } + } else { + if (Variable >= GetEndPointer (StoreInfo->VariableStoreHeader)) { + // + // Reach the end of variable store. + // + return FALSE; + } + } + + return IsValidVariableHeader (*VariableHeader); +} + +/** + Get variable name or data to output buffer. + + @param[in] StoreInfo Pointer to variable store info structure. + @param[in] NameOrData Pointer to the variable name/data that may be inconsecutive. + @param[in] Size Variable name/data size. + @param[out] Buffer Pointer to output buffer to hold the variable name/data. + +**/ +VOID +GetVariableNameOrData ( + IN VARIABLE_STORE_INFO *StoreInfo, + IN UINT8 *NameOrData, + IN UINTN Size, + OUT UINT8 *Buffer + ) +{ + EFI_PHYSICAL_ADDRESS TargetAddress; + EFI_PHYSICAL_ADDRESS SpareAddress; + UINTN PartialSize; + + if (StoreInfo->FtwLastWriteData != NULL) { + TargetAddress = StoreInfo->FtwLastWriteData->TargetAddress; + SpareAddress = StoreInfo->FtwLastWriteData->SpareAddress; + if (((UINTN)NameOrData < (UINTN)TargetAddress) && (((UINTN)NameOrData + Size) > (UINTN)TargetAddress)) { + // + // Variable name/data is inconsecutive. + // + PartialSize = (UINTN)TargetAddress - (UINTN)NameOrData; + // + // Partial content is in NV storage. + // + CopyMem (Buffer, NameOrData, PartialSize); + // + // Another partial content is in spare block. + // + CopyMem (Buffer + PartialSize, (UINT8 *)(UINTN)SpareAddress, Size - PartialSize); + return; + } + } + + // + // Variable name/data is consecutive. + // + CopyMem (Buffer, NameOrData, Size); +} + +/** + + Internal function to retrieve variable information. + + @param[in,out] VariableInfo Pointer to variable information. + @param[in] StoreInfo Pointer to store copy of variable (optional). + @param[in] VariablePtr Pointer to variable buffer. + @param[in] VariableHeader Pointer to variable header. + + @retval EFI_INVALID_PARAMETER One ore more required parameters are NULL. + @retval EFI_BUFFER_TOO_SMALL Given buffer is too small to hold data. + @retval EFI_SUCCESS Variable details are retrieved successfully. + +**/ +EFI_STATUS +EFIAPI +GetVariableInfoInternal ( + IN OUT PROTECTED_VARIABLE_INFO *VariableInfo, + IN VARIABLE_STORE_INFO *StoreInfo OPTIONAL, + IN VARIABLE_HEADER *VariablePtr, + IN VARIABLE_HEADER *VariableHeader + ) +{ + VARIABLE_HEADER *VariableBuffer; + AUTHENTICATED_VARIABLE_HEADER *AuthVariableHeader; + UINTN NameSize; + UINTN DataSize; + UINTN VariableSize; + + if ((VariableInfo == NULL) || (VariablePtr == NULL) || (VariableHeader == NULL)) { + ASSERT (VariableInfo != NULL); + ASSERT (VariablePtr != NULL); + ASSERT (VariableHeader != NULL); + return EFI_INVALID_PARAMETER; + } + + VariableBuffer = VariableInfo->Buffer; + + // + // Make a copy of the whole variable if VariableInfo->Buffer is given. But + // don't do this if StoreInfo is not given, because VariableInfo->Buffer + // has already hold a copy of variable in such situation. + // + NameSize = NameSizeOfVariable (VariableHeader, VariableInfo->Flags.Auth); + DataSize = DataSizeOfVariable (VariableHeader, VariableInfo->Flags.Auth); + if ((VariableBuffer != NULL) && (VariableBuffer != VariablePtr)) { + if (StoreInfo != NULL) { + CopyMem ( + VariableBuffer, + VariableHeader, + GetVariableHeaderSize (VariableInfo->Flags.Auth) + ); + GetVariableNameOrData ( + StoreInfo, + (UINT8 *)GetVariableNamePtr (VariablePtr, VariableInfo->Flags.Auth), + NameSize, + (UINT8 *)GetVariableNamePtr (VariableBuffer, VariableInfo->Flags.Auth) + ); + GetVariableNameOrData ( + StoreInfo, + (UINT8 *)GetVariableDataPtr (VariablePtr, VariableHeader, VariableInfo->Flags.Auth), + DataSize, + (UINT8 *)GetVariableDataPtr (VariableBuffer, VariableHeader, VariableInfo->Flags.Auth) + ); + } else { + // + // Suppose the variable is in consecutive space. + // + VariableSize = GetVariableHeaderSize (VariableInfo->Flags.Auth) + + NameSize + GET_PAD_SIZE (NameSize) + + DataSize; + CopyMem (VariableBuffer, VariablePtr, VariableSize); + } + } + + // + // Generally, if no consecutive buffer passed in, don't return back any data. + // + // If follow pointers are NULL, return back pointers to following data inside + // VariableInfo->Buffer, if it's given. + // + // VariableInfo->Header.VariableName + // VariableInfo->Header.Data + // VariableInfo->Header.VendorGuid + // VariableInfo->Header.TimeStamp + // + // Otherwise, suppose they're buffers used to hold a copy of corresponding + // data. + // + // + + // + // AuthVariable header + // + if (VariableInfo->Flags.Auth) { + AuthVariableHeader = (AUTHENTICATED_VARIABLE_HEADER *)VariableHeader; + + VariableInfo->Header.State = AuthVariableHeader->State; + VariableInfo->Header.Attributes = AuthVariableHeader->Attributes; + VariableInfo->Header.PubKeyIndex = AuthVariableHeader->PubKeyIndex; + VariableInfo->Header.MonotonicCount = ReadUnaligned64 ( + &(AuthVariableHeader->MonotonicCount) + ); + if (VariableInfo->Header.TimeStamp != NULL) { + CopyMem ( + VariableInfo->Header.TimeStamp, + &AuthVariableHeader->TimeStamp, + sizeof (EFI_TIME) + ); + } else if (VariableBuffer != NULL) { + AuthVariableHeader = (AUTHENTICATED_VARIABLE_HEADER *)VariableBuffer; + VariableInfo->Header.TimeStamp = &AuthVariableHeader->TimeStamp; + } + } else { + VariableInfo->Header.State = VariableHeader->State; + VariableInfo->Header.Attributes = VariableHeader->Attributes; + VariableInfo->Header.PubKeyIndex = 0; + VariableInfo->Header.MonotonicCount = 0; + VariableInfo->Header.TimeStamp = NULL; + } + + // + // VendorGuid + // + if (VariableInfo->Header.VendorGuid != NULL) { + CopyGuid ( + VariableInfo->Header.VendorGuid, + GetVendorGuidPtr (VariableHeader, VariableInfo->Flags.Auth) + ); + } else if (VariableBuffer != NULL) { + VariableInfo->Header.VendorGuid + = GetVendorGuidPtr (VariableBuffer, VariableInfo->Flags.Auth); + } + + // + // VariableName + // + if ( (VariableInfo->Header.VariableName != NULL) + && (VariableInfo->Header.NameSize >= NameSize)) + { + GetVariableNameOrData ( + StoreInfo, + (UINT8 *)GetVariableNamePtr (VariablePtr, VariableInfo->Flags.Auth), + NameSize, + (UINT8 *)VariableInfo->Header.VariableName + ); + } else if (VariableBuffer != NULL) { + VariableInfo->Header.VariableName + = GetVariableNamePtr (VariableBuffer, VariableInfo->Flags.Auth); + } else if (VariableInfo->Header.VariableName != NULL) { + return EFI_BUFFER_TOO_SMALL; + } + + // + // Data + // + if ( (VariableInfo->Header.Data != NULL) + && (VariableInfo->Header.DataSize >= DataSize)) + { + GetVariableNameOrData ( + StoreInfo, + GetVariableDataPtr (VariablePtr, VariableHeader, StoreInfo->AuthFlag), + DataSize, + VariableInfo->Header.Data + ); + } else if (VariableBuffer != NULL) { + VariableInfo->Header.Data + = GetVariableDataPtr (VariableBuffer, VariableBuffer, VariableInfo->Flags.Auth); + } else if (VariableInfo->Header.Data != NULL) { + return EFI_BUFFER_TOO_SMALL; + } + + // + // Update size information about name & data. + // + VariableInfo->Header.NameSize = NameSize; + VariableInfo->Header.DataSize = DataSize; + + return EFI_SUCCESS; +} + +/** + + Retrieve details about a variable, given by VariableInfo->Buffer or + VariableInfo->Index, and pass the details back in VariableInfo->Header. + + This function is used to resolve the variable data structure into + VariableInfo->Header, for easier access later without revisiting the variable + data in variable store. If pointers in the structure of VariableInfo->Header + are not NULL, it's supposed that they are buffers passed in to hold a copy of + data of corresponding data fields in variable data structure. Otherwise, this + function simply returns pointers pointing to address of those data fields. + + The variable is specified by either VariableInfo->Index or VariableInfo->Buffer. + If VariableInfo->Index is given, this function finds the corresponding variable + first from variable storage according to the Index. + + If both VariableInfo->Index and VariableInfo->Buffer are given, it's supposed + that VariableInfo->Buffer is a buffer passed in to hold a whole copy of + requested variable data to be returned. + + @param[in,out] VariableInfo Pointer to variable information. + + @retval EFI_INVALID_PARAMETER VariableInfo is NULL or both VariableInfo->Buffer + and VariableInfo->Index are NULL (0). + @retval EFI_NOT_FOUND If given Buffer or Index is out of range of + any given or internal storage copies. + @retval EFI_SUCCESS Variable details are retrieved successfully. + +**/ +EFI_STATUS +EFIAPI +GetVariableInfo ( + IN OUT PROTECTED_VARIABLE_INFO *VariableInfo + ) +{ + VARIABLE_HEADER *VariablePtr; + VARIABLE_HEADER *VariableHeader; + VARIABLE_STORE_TYPE StoreType; + VARIABLE_STORE_INFO StoreInfo; + UINTN Offset; + + if ((VariableInfo == NULL) || + ((VariableInfo->Buffer == NULL) && (VariableInfo->StoreIndex == VAR_INDEX_INVALID))) + { + ASSERT (VariableInfo != NULL); + ASSERT (VariableInfo->StoreIndex != VAR_INDEX_INVALID || VariableInfo->Buffer != NULL); + return EFI_INVALID_PARAMETER; + } + + StoreInfo.VariableStoreHeader = NULL; + for (StoreType = VariableStoreTypeHob; StoreType < VariableStoreTypeMax; ++StoreType) { + GetVariableStore (StoreType, &StoreInfo); + if (StoreInfo.VariableStoreHeader != NULL) { + break; + } + } + + ASSERT (StoreInfo.VariableStoreHeader != NULL); + + // + // No StoreIndex? Don't retrieve variable information from store but just from + // VariableInfo->Buffer. + // + if (VariableInfo->StoreIndex == VAR_INDEX_INVALID) { + VariablePtr = VariableInfo->Buffer; + VariableHeader = VariablePtr; + + return GetVariableInfoInternal (VariableInfo, NULL, VariablePtr, VariableHeader); + } + + Offset = (UINTN)VariableInfo->StoreIndex; + if ( (StoreInfo.FtwLastWriteData != NULL) + && (Offset >= ((UINTN)StoreInfo.FtwLastWriteData->TargetAddress + - (UINTN)StoreInfo.VariableStoreHeader))) + { + Offset -= ((UINTN)StoreInfo.FtwLastWriteData->TargetAddress + - (UINTN)StoreInfo.VariableStoreHeader); + VariablePtr = (VARIABLE_HEADER *) + ((UINTN)StoreInfo.FtwLastWriteData->SpareAddress + Offset); + } else { + VariablePtr = (VARIABLE_HEADER *) + ((UINTN)StoreInfo.VariableStoreHeader + Offset); + } + + // + // Note that variable might be in unconsecutive space. Always get a copy + // of its header in consecutive buffer. + // + if (!GetVariableHeader (&StoreInfo, VariablePtr, &VariableHeader)) { + return EFI_NOT_FOUND; + } + + return GetVariableInfoInternal (VariableInfo, &StoreInfo, VariablePtr, VariableHeader); +} + +/** + + Retrieve details of the variable next to given variable within VariableStore. + + If VarInfo->Buffer is NULL, the first one in VariableStore is returned. + + VariableStart and/or VariableEnd can be given optionally for the situation + in which the valid storage space is smaller than the VariableStore->Size. + This usually happens when PEI variable services make a compact variable + cache to save memory, which cannot make use VariableStore->Size to determine + the correct variable storage range. + + @param[in,out] VariableInfo Pointer to variable information. + + @retval EFI_INVALID_PARAMETER VariableInfo or VariableStore is NULL. + @retval EFI_NOT_FOUND If the end of VariableStore is reached. + @retval EFI_SUCCESS The next variable is retrieved successfully. + +**/ +EFI_STATUS +EFIAPI +GetNextVariableInfo ( + IN OUT PROTECTED_VARIABLE_INFO *VariableInfo + ) +{ + VARIABLE_HEADER *VariablePtr; + VARIABLE_HEADER *VariableHeader; + VARIABLE_STORE_INFO StoreInfo; + VARIABLE_STORE_TYPE StoreType; + UINTN Offset; + + if (VariableInfo == NULL) { + ASSERT (VariableInfo != NULL); + return EFI_INVALID_PARAMETER; + } + + StoreInfo.VariableStoreHeader = NULL; + for (StoreType = VariableStoreTypeHob; StoreType < VariableStoreTypeMax; ++StoreType) { + GetVariableStore (StoreType, &StoreInfo); + if (StoreInfo.VariableStoreHeader != NULL) { + break; + } + } + + ASSERT (StoreInfo.VariableStoreHeader != NULL); + + // + // VariableInfo->StoreIndex is supposed to be the index to variable found + // last time. Use it to get the variable next to it in store. If it's invalid, + // return the first variable available in store. + // + VariableInfo->Flags.Auth = StoreInfo.AuthFlag; + if (VariableInfo->StoreIndex == VAR_INDEX_INVALID) { + VariablePtr = GetStartPointer (StoreInfo.VariableStoreHeader); + } else { + Offset = (UINTN)VariableInfo->StoreIndex; + if ( (StoreInfo.FtwLastWriteData != NULL) + && (Offset >= ((UINTN)StoreInfo.FtwLastWriteData->TargetAddress + - (UINTN)StoreInfo.VariableStoreHeader))) + { + Offset -= ((UINTN)StoreInfo.FtwLastWriteData->TargetAddress + - (UINTN)StoreInfo.VariableStoreHeader); + VariablePtr = (VARIABLE_HEADER *) + ((UINTN)StoreInfo.FtwLastWriteData->SpareAddress + Offset); + } else { + VariablePtr = (VARIABLE_HEADER *) + ((UINTN)StoreInfo.VariableStoreHeader + Offset); + } + + // + // Note that variable might be in unconsecutive space. Always get a copy + // of its header in consecutive buffer. + // + if (!GetVariableHeader (&StoreInfo, VariablePtr, &VariableHeader)) { + return EFI_NOT_FOUND; + } + + VariablePtr = GetNextVariablePtr (&StoreInfo, VariablePtr, VariableHeader); + } + + // + // Get a copy of variable header in consecutive buffer. + // + if (!GetVariableHeader (&StoreInfo, VariablePtr, &VariableHeader)) { + return EFI_NOT_FOUND; + } + + // + // Use the offset to the start of variable store as index of the variable. + // + if ( (StoreInfo.FtwLastWriteData == NULL) + || ((UINTN)VariablePtr < (UINTN)StoreInfo.FtwLastWriteData->TargetAddress)) + { + VariableInfo->StoreIndex + = (UINT64)((UINTN)VariablePtr - (UINTN)StoreInfo.VariableStoreHeader); + } else { + VariableInfo->StoreIndex + = (UINT64)((UINTN)StoreInfo.FtwLastWriteData->TargetAddress + - (UINTN)StoreInfo.VariableStoreHeader); + VariableInfo->StoreIndex + += (UINT64)((UINTN)VariablePtr - (UINTN)StoreInfo.FtwLastWriteData->SpareAddress); + } + + if ((StoreType == VariableStoreTypeHob) && (VariableInfo->Buffer == NULL)) { + VariableInfo->Buffer = VariablePtr; + } + + return GetVariableInfoInternal (VariableInfo, &StoreInfo, VariablePtr, VariableHeader); +} diff --git a/MdeModulePkg/Universal/Variable/Pei/VariableStore.c b/MdeModulePkg/Universal/Variable/Pei/VariableStore.c new file mode 100644 index 000000000000..75edc3fc5051 --- /dev/null +++ b/MdeModulePkg/Universal/Variable/Pei/VariableStore.c @@ -0,0 +1,307 @@ +/** @file + Implement ReadOnly Variable Services required by PEIM and install + PEI ReadOnly Varaiable2 PPI. These services operates the non volatile storage space. + +Copyright (c) 2022, Intel Corporation. All rights reserved.
+SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "VariableParsing.h" +#include "VariableStore.h" + +/** + Get variable store status. + + @param[in] VarStoreHeader Pointer to the Variable Store Header. + + @retval EfiRaw Variable store is raw + @retval EfiValid Variable store is valid + @retval EfiInvalid Variable store is invalid + +**/ +VARIABLE_STORE_STATUS +GetVariableStoreStatus ( + IN VARIABLE_STORE_HEADER *VarStoreHeader + ) +{ + if ((CompareGuid (&VarStoreHeader->Signature, &gEfiAuthenticatedVariableGuid) || + CompareGuid (&VarStoreHeader->Signature, &gEfiVariableGuid)) && + (VarStoreHeader->Format == VARIABLE_STORE_FORMATTED) && + (VarStoreHeader->State == VARIABLE_STORE_HEALTHY) + ) + { + return EfiValid; + } + + if ((((UINT32 *)(&VarStoreHeader->Signature))[0] == 0xffffffff) && + (((UINT32 *)(&VarStoreHeader->Signature))[1] == 0xffffffff) && + (((UINT32 *)(&VarStoreHeader->Signature))[2] == 0xffffffff) && + (((UINT32 *)(&VarStoreHeader->Signature))[3] == 0xffffffff) && + (VarStoreHeader->Size == 0xffffffff) && + (VarStoreHeader->Format == 0xff) && + (VarStoreHeader->State == 0xff) + ) + { + return EfiRaw; + } else { + return EfiInvalid; + } +} + +/** + Reports HOB variable store is available or not. + + @retval EFI_NOT_READY HOB variable store info not available. + @retval EFI_NOT_FOUND HOB variable store is NOT available. + @retval EFI_SUCCESS HOB variable store is available. +**/ +EFI_STATUS +EFIAPI +IsHobVariableStoreAvailable ( + VOID + ) +{ + EFI_HOB_GUID_TYPE *GuidHob; + VOID *VariableStoreInfoHob; + + // + // Discover if Variable Store Info Hob has been published by platform driver. + // It contains information regards to HOB or NV Variable Store availability + // + GuidHob = GetFirstGuidHob (&gEfiPeiVariableStoreDiscoveredPpiGuid); + if (GuidHob == NULL) { + return EFI_NOT_READY; + } + + // + // Check if HOB Variable Store is available + // + VariableStoreInfoHob = GET_GUID_HOB_DATA (GuidHob); + if (*(BOOLEAN *)VariableStoreInfoHob == TRUE) { + return EFI_SUCCESS; + } + + // + // This might be NV Variable Store + // + return EFI_NOT_FOUND; +} + +/** + Get HOB variable store. + + @param[out] StoreInfo Return the store info. + +**/ +VOID +GetHobVariableStore ( + OUT VARIABLE_STORE_INFO *StoreInfo + ) +{ + EFI_HOB_GUID_TYPE *GuidHob; + + // + // Make sure there is no more than one Variable HOB. + // + DEBUG_CODE_BEGIN (); + GuidHob = GetFirstGuidHob (&gEfiAuthenticatedVariableGuid); + if (GuidHob != NULL) { + if ((GetNextGuidHob (&gEfiAuthenticatedVariableGuid, GET_NEXT_HOB (GuidHob)) != NULL)) { + DEBUG ((DEBUG_ERROR, "ERROR: Found two Auth Variable HOBs\n")); + ASSERT (FALSE); + } else if (GetFirstGuidHob (&gEfiVariableGuid) != NULL) { + DEBUG ((DEBUG_ERROR, "ERROR: Found one Auth + one Normal Variable HOBs\n")); + ASSERT (FALSE); + } + } else { + GuidHob = GetFirstGuidHob (&gEfiVariableGuid); + if (GuidHob != NULL) { + if ((GetNextGuidHob (&gEfiVariableGuid, GET_NEXT_HOB (GuidHob)) != NULL)) { + DEBUG ((DEBUG_ERROR, "ERROR: Found two Normal Variable HOBs\n")); + ASSERT (FALSE); + } + } + } + + DEBUG_CODE_END (); + + GuidHob = GetFirstGuidHob (&gEfiAuthenticatedVariableGuid); + if (GuidHob != NULL) { + StoreInfo->VariableStoreHeader = (VARIABLE_STORE_HEADER *)GET_GUID_HOB_DATA (GuidHob); + StoreInfo->AuthFlag = TRUE; + } else { + GuidHob = GetFirstGuidHob (&gEfiVariableGuid); + if (GuidHob != NULL) { + StoreInfo->VariableStoreHeader = (VARIABLE_STORE_HEADER *)GET_GUID_HOB_DATA (GuidHob); + StoreInfo->AuthFlag = FALSE; + } + } +} + +/** + Get NV variable store. + + @param[out] StoreInfo Return the store info. + @param[out] VariableFvHeader Return header of FV containing the store. + +**/ +VOID +GetNvVariableStore ( + OUT VARIABLE_STORE_INFO *StoreInfo, + OUT EFI_FIRMWARE_VOLUME_HEADER **VariableFvHeader + ) +{ + EFI_STATUS Status; + EFI_HOB_GUID_TYPE *GuidHob; + EFI_FIRMWARE_VOLUME_HEADER *FvHeader; + VARIABLE_STORE_HEADER *StoreHeader; + FAULT_TOLERANT_WRITE_LAST_WRITE_DATA *HobData; + FAULT_TOLERANT_WRITE_LAST_WRITE_DATA *FtwLastWriteData; + EFI_PHYSICAL_ADDRESS NvStorageBase; + UINT32 NvStorageSize; + UINT32 BackUpOffset; + UINT64 NvStorageSize64; + + Status = GetVariableFlashNvStorageInfo (&NvStorageBase, &NvStorageSize64); + ASSERT_EFI_ERROR (Status); + + Status = SafeUint64ToUint32 (NvStorageSize64, &NvStorageSize); + // This driver currently assumes the size will be UINT32 so assert the value is safe for now. + ASSERT_EFI_ERROR (Status); + + FvHeader = (EFI_FIRMWARE_VOLUME_HEADER *)(UINTN)NvStorageBase; + + // + // Check the FTW last write data hob. + // + BackUpOffset = 0; + FtwLastWriteData = NULL; + HobData = NULL; + GuidHob = GetFirstGuidHob (&gEdkiiFaultTolerantWriteGuid); + + if (GuidHob != NULL) { + HobData = (FAULT_TOLERANT_WRITE_LAST_WRITE_DATA *)GET_GUID_HOB_DATA (GuidHob); + if (HobData->TargetAddress == NvStorageBase) { + // + // Let FvHeader point to spare block. + // + DEBUG (( + EFI_D_INFO, + "PeiVariable: NV storage is backed up in spare block: 0x%x\n", + (UINTN)HobData->SpareAddress + )); + + FvHeader = (EFI_FIRMWARE_VOLUME_HEADER *)(UINTN)HobData->SpareAddress; + HobData = NULL; + } else if ((HobData->TargetAddress > NvStorageBase) && + (HobData->TargetAddress < (NvStorageBase + NvStorageSize))) + { + // + // Flash NV storage from the offset is backed up in spare block. + // + BackUpOffset = (UINT32)(HobData->TargetAddress - NvStorageBase); + DEBUG (( + EFI_D_INFO, + "PeiVariable: High partial NV storage from offset: %x is backed up in spare block: 0x%x\n", + BackUpOffset, + (UINTN)FtwLastWriteData->SpareAddress + )); + // + // At least one block data in flash NV storage is still valid, so still + // leave FvHeader point to NV storage base. + // + } + } + + if (StoreInfo != NULL) { + StoreInfo->FtwLastWriteData = HobData; + } + + if (VariableFvHeader != NULL) { + *VariableFvHeader = FvHeader; + } + + // + // Check if the Firmware Volume is not corrupted + // + if ((FvHeader->Signature == EFI_FVH_SIGNATURE) && + CompareGuid (&gEfiSystemNvDataFvGuid, &FvHeader->FileSystemGuid)) + { + StoreHeader = (VARIABLE_STORE_HEADER *)((UINTN)FvHeader + FvHeader->HeaderLength); + } else { + StoreHeader = NULL; + DEBUG ((DEBUG_ERROR, "Firmware Volume for Variable Store is corrupted\n")); + } + + if (StoreInfo != NULL) { + StoreInfo->VariableStoreHeader = StoreHeader; + if (StoreHeader != NULL) { + StoreInfo->AuthFlag = CompareGuid ( + &StoreHeader->Signature, + &gEfiAuthenticatedVariableGuid + ); + } + } +} + +/** + Return the variable store header and the store info based on the Index. + + @param[in] Type The type of the variable store. + @param[out] StoreInfo Return the store info. + + @return Pointer to the variable store header. +**/ +VARIABLE_STORE_HEADER * +GetVariableStore ( + IN VARIABLE_STORE_TYPE Type, + OUT VARIABLE_STORE_INFO *StoreInfo + ) +{ + EFI_HOB_GUID_TYPE *GuidHob; + + StoreInfo->VariableStoreHeader = NULL; + StoreInfo->IndexTable = NULL; + StoreInfo->FtwLastWriteData = NULL; + StoreInfo->AuthFlag = FALSE; + switch (Type) { + case VariableStoreTypeHob: + GetHobVariableStore (StoreInfo); + break; + + case VariableStoreTypeNv: + if (!PcdGetBool (PcdEmuVariableNvModeEnable)) { + // + // Emulated non-volatile variable mode is not enabled. + // + GetNvVariableStore (StoreInfo, NULL); + if (StoreInfo->VariableStoreHeader != NULL) { + GuidHob = GetFirstGuidHob (&gEfiVariableIndexTableGuid); + if (GuidHob != NULL) { + StoreInfo->IndexTable = GET_GUID_HOB_DATA (GuidHob); + } else { + // + // If it's the first time to access variable region in flash, create a guid hob to record + // VAR_ADDED type variable info. + // Note that as the resource of PEI phase is limited, only store the limited number of + // VAR_ADDED type variables to reduce access time. + // + StoreInfo->IndexTable = (VARIABLE_INDEX_TABLE *)BuildGuidHob (&gEfiVariableIndexTableGuid, sizeof (VARIABLE_INDEX_TABLE)); + StoreInfo->IndexTable->Length = 0; + StoreInfo->IndexTable->StartPtr = GetStartPointer (StoreInfo->VariableStoreHeader); + StoreInfo->IndexTable->EndPtr = GetEndPointer (StoreInfo->VariableStoreHeader); + StoreInfo->IndexTable->GoneThrough = 0; + } + } + } + + break; + + default: + ASSERT (FALSE); + break; + } + + return StoreInfo->VariableStoreHeader; +} -- 2.35.1.windows.2