REF:https://bugzilla.tianocore.org/show_bug.cgi?id=3479 Updates VariableRuntimeDxe, VariableSmm, and VariableStandaloneMm to acquire variable flash information from the Variable Flash Information library. Note: This introduces a dependency on VariableFlashInfoLib in these modules. Therefore, a platform building the variable modules must specify an instance of VariableFlashInfoLib in their platform build. Cc: Jian J Wang <jian.j.wang@intel.com> Cc: Hao A Wu <hao.a.wu@intel.com> Cc: Liming Gao <gaoliming@byosoft.com.cn> Signed-off-by: Michael Kubacki <michael.kubacki@microsoft.com> Acked-by: Ard Biesheuvel <ardb@kernel.org> Reviewed-by: Liming Gao <gaoliming@byosoft.com.cn> Reviewed-by: Sami Mujawar <sami.mujawar@arm.com>
		
			
				
	
	
		
			348 lines
		
	
	
		
			14 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			348 lines
		
	
	
		
			14 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /** @file
 | |
|   Common variable non-volatile store routines.
 | |
| 
 | |
| Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>
 | |
| SPDX-License-Identifier: BSD-2-Clause-Patent
 | |
| 
 | |
| **/
 | |
| 
 | |
| #include "VariableNonVolatile.h"
 | |
| #include "VariableParsing.h"
 | |
| 
 | |
| extern VARIABLE_MODULE_GLOBAL  *mVariableModuleGlobal;
 | |
| 
 | |
| /**
 | |
|   Get non-volatile maximum variable size.
 | |
| 
 | |
|   @return Non-volatile maximum variable size.
 | |
| 
 | |
| **/
 | |
| UINTN
 | |
| GetNonVolatileMaxVariableSize (
 | |
|   VOID
 | |
|   )
 | |
| {
 | |
|   if (PcdGet32 (PcdHwErrStorageSize) != 0) {
 | |
|     return MAX (
 | |
|              MAX (PcdGet32 (PcdMaxVariableSize), PcdGet32 (PcdMaxAuthVariableSize)),
 | |
|              PcdGet32 (PcdMaxHardwareErrorVariableSize)
 | |
|              );
 | |
|   } else {
 | |
|     return MAX (PcdGet32 (PcdMaxVariableSize), PcdGet32 (PcdMaxAuthVariableSize));
 | |
|   }
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Init emulated non-volatile variable store.
 | |
| 
 | |
|   @param[out] VariableStoreBase Output pointer to emulated non-volatile variable store base.
 | |
| 
 | |
|   @retval EFI_SUCCESS           Function successfully executed.
 | |
|   @retval EFI_OUT_OF_RESOURCES  Fail to allocate enough memory resource.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| InitEmuNonVolatileVariableStore (
 | |
|   OUT EFI_PHYSICAL_ADDRESS  *VariableStoreBase
 | |
|   )
 | |
| {
 | |
|   VARIABLE_STORE_HEADER  *VariableStore;
 | |
|   UINT32                 VariableStoreLength;
 | |
|   BOOLEAN                FullyInitializeStore;
 | |
|   UINT32                 HwErrStorageSize;
 | |
| 
 | |
|   FullyInitializeStore = TRUE;
 | |
| 
 | |
|   VariableStoreLength = PcdGet32 (PcdVariableStoreSize);
 | |
|   ASSERT (sizeof (VARIABLE_STORE_HEADER) <= VariableStoreLength);
 | |
| 
 | |
|   //
 | |
|   // Allocate memory for variable store.
 | |
|   //
 | |
|   if (PcdGet64 (PcdEmuVariableNvStoreReserved) == 0) {
 | |
|     VariableStore = (VARIABLE_STORE_HEADER *)AllocateRuntimePool (VariableStoreLength);
 | |
|     if (VariableStore == NULL) {
 | |
|       return EFI_OUT_OF_RESOURCES;
 | |
|     }
 | |
|   } else {
 | |
|     //
 | |
|     // A memory location has been reserved for the NV variable store.  Certain
 | |
|     // platforms may be able to preserve a memory range across system resets,
 | |
|     // thereby providing better NV variable emulation.
 | |
|     //
 | |
|     VariableStore =
 | |
|       (VARIABLE_STORE_HEADER *)(VOID *)(UINTN)
 | |
|       PcdGet64 (PcdEmuVariableNvStoreReserved);
 | |
|     if ((VariableStore->Size == VariableStoreLength) &&
 | |
|         (CompareGuid (&VariableStore->Signature, &gEfiAuthenticatedVariableGuid) ||
 | |
|          CompareGuid (&VariableStore->Signature, &gEfiVariableGuid)) &&
 | |
|         (VariableStore->Format == VARIABLE_STORE_FORMATTED) &&
 | |
|         (VariableStore->State == VARIABLE_STORE_HEALTHY))
 | |
|     {
 | |
|       DEBUG ((
 | |
|         DEBUG_INFO,
 | |
|         "Variable Store reserved at %p appears to be valid\n",
 | |
|         VariableStore
 | |
|         ));
 | |
|       FullyInitializeStore = FALSE;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   if (FullyInitializeStore) {
 | |
|     SetMem (VariableStore, VariableStoreLength, 0xff);
 | |
|     //
 | |
|     // Use gEfiAuthenticatedVariableGuid for potential auth variable support.
 | |
|     //
 | |
|     CopyGuid (&VariableStore->Signature, &gEfiAuthenticatedVariableGuid);
 | |
|     VariableStore->Size      = VariableStoreLength;
 | |
|     VariableStore->Format    = VARIABLE_STORE_FORMATTED;
 | |
|     VariableStore->State     = VARIABLE_STORE_HEALTHY;
 | |
|     VariableStore->Reserved  = 0;
 | |
|     VariableStore->Reserved1 = 0;
 | |
|   }
 | |
| 
 | |
|   *VariableStoreBase = (EFI_PHYSICAL_ADDRESS)(UINTN)VariableStore;
 | |
| 
 | |
|   HwErrStorageSize = PcdGet32 (PcdHwErrStorageSize);
 | |
| 
 | |
|   //
 | |
|   // Note that in EdkII variable driver implementation, Hardware Error Record type variable
 | |
|   // is stored with common variable in the same NV region. So the platform integrator should
 | |
|   // ensure that the value of PcdHwErrStorageSize is less than the value of
 | |
|   // (VariableStoreLength - sizeof (VARIABLE_STORE_HEADER)).
 | |
|   //
 | |
|   ASSERT (HwErrStorageSize < (VariableStoreLength - sizeof (VARIABLE_STORE_HEADER)));
 | |
| 
 | |
|   mVariableModuleGlobal->CommonVariableSpace        = ((UINTN)VariableStoreLength - sizeof (VARIABLE_STORE_HEADER) - HwErrStorageSize);
 | |
|   mVariableModuleGlobal->CommonMaxUserVariableSpace = mVariableModuleGlobal->CommonVariableSpace;
 | |
|   mVariableModuleGlobal->CommonRuntimeVariableSpace = mVariableModuleGlobal->CommonVariableSpace;
 | |
| 
 | |
|   return EFI_SUCCESS;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Init real non-volatile variable store.
 | |
| 
 | |
|   @param[out] VariableStoreBase Output pointer to real non-volatile variable store base.
 | |
| 
 | |
|   @retval EFI_SUCCESS           Function successfully executed.
 | |
|   @retval EFI_OUT_OF_RESOURCES  Fail to allocate enough memory resource.
 | |
|   @retval EFI_VOLUME_CORRUPTED  Variable Store or Firmware Volume for Variable Store is corrupted.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| InitRealNonVolatileVariableStore (
 | |
|   OUT EFI_PHYSICAL_ADDRESS  *VariableStoreBase
 | |
|   )
 | |
| {
 | |
|   EFI_FIRMWARE_VOLUME_HEADER            *FvHeader;
 | |
|   VARIABLE_STORE_HEADER                 *VariableStore;
 | |
|   UINT32                                VariableStoreLength;
 | |
|   EFI_HOB_GUID_TYPE                     *GuidHob;
 | |
|   EFI_PHYSICAL_ADDRESS                  NvStorageBase;
 | |
|   UINT8                                 *NvStorageData;
 | |
|   UINT32                                NvStorageSize;
 | |
|   UINT64                                NvStorageSize64;
 | |
|   FAULT_TOLERANT_WRITE_LAST_WRITE_DATA  *FtwLastWriteData;
 | |
|   UINT32                                BackUpOffset;
 | |
|   UINT32                                BackUpSize;
 | |
|   UINT32                                HwErrStorageSize;
 | |
|   UINT32                                MaxUserNvVariableSpaceSize;
 | |
|   UINT32                                BoottimeReservedNvVariableSpaceSize;
 | |
|   EFI_STATUS                            Status;
 | |
|   VOID                                  *FtwProtocol;
 | |
| 
 | |
|   mVariableModuleGlobal->FvbInstance = NULL;
 | |
| 
 | |
|   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);
 | |
| 
 | |
|   //
 | |
|   // Allocate runtime memory used for a memory copy of the FLASH region.
 | |
|   // Keep the memory and the FLASH in sync as updates occur.
 | |
|   //
 | |
|   NvStorageData = AllocateRuntimeZeroPool (NvStorageSize);
 | |
|   if (NvStorageData == NULL) {
 | |
|     return EFI_OUT_OF_RESOURCES;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Copy NV storage data to the memory buffer.
 | |
|   //
 | |
|   CopyMem (NvStorageData, (UINT8 *)(UINTN)NvStorageBase, NvStorageSize);
 | |
| 
 | |
|   Status = GetFtwProtocol ((VOID **)&FtwProtocol);
 | |
|   //
 | |
|   // If FTW protocol has been installed, no need to check FTW last write data hob.
 | |
|   //
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     //
 | |
|     // Check the FTW last write data hob.
 | |
|     //
 | |
|     GuidHob = GetFirstGuidHob (&gEdkiiFaultTolerantWriteGuid);
 | |
|     if (GuidHob != NULL) {
 | |
|       FtwLastWriteData = (FAULT_TOLERANT_WRITE_LAST_WRITE_DATA *)GET_GUID_HOB_DATA (GuidHob);
 | |
|       if (FtwLastWriteData->TargetAddress == NvStorageBase) {
 | |
|         DEBUG ((DEBUG_INFO, "Variable: NV storage is backed up in spare block: 0x%x\n", (UINTN)FtwLastWriteData->SpareAddress));
 | |
|         //
 | |
|         // Copy the backed up NV storage data to the memory buffer from spare block.
 | |
|         //
 | |
|         CopyMem (NvStorageData, (UINT8 *)(UINTN)(FtwLastWriteData->SpareAddress), NvStorageSize);
 | |
|       } else if ((FtwLastWriteData->TargetAddress > NvStorageBase) &&
 | |
|                  (FtwLastWriteData->TargetAddress < (NvStorageBase + NvStorageSize)))
 | |
|       {
 | |
|         //
 | |
|         // Flash NV storage from the Offset is backed up in spare block.
 | |
|         //
 | |
|         BackUpOffset = (UINT32)(FtwLastWriteData->TargetAddress - NvStorageBase);
 | |
|         BackUpSize   = NvStorageSize - BackUpOffset;
 | |
|         DEBUG ((DEBUG_INFO, "Variable: High partial NV storage from offset: %x is backed up in spare block: 0x%x\n", BackUpOffset, (UINTN)FtwLastWriteData->SpareAddress));
 | |
|         //
 | |
|         // Copy the partial backed up NV storage data to the memory buffer from spare block.
 | |
|         //
 | |
|         CopyMem (NvStorageData + BackUpOffset, (UINT8 *)(UINTN)FtwLastWriteData->SpareAddress, BackUpSize);
 | |
|       }
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   FvHeader = (EFI_FIRMWARE_VOLUME_HEADER *)NvStorageData;
 | |
| 
 | |
|   //
 | |
|   // Check if the Firmware Volume is not corrupted
 | |
|   //
 | |
|   if ((FvHeader->Signature != EFI_FVH_SIGNATURE) || (!CompareGuid (&gEfiSystemNvDataFvGuid, &FvHeader->FileSystemGuid))) {
 | |
|     FreePool (NvStorageData);
 | |
|     DEBUG ((DEBUG_ERROR, "Firmware Volume for Variable Store is corrupted\n"));
 | |
|     return EFI_VOLUME_CORRUPTED;
 | |
|   }
 | |
| 
 | |
|   VariableStore       = (VARIABLE_STORE_HEADER *)((UINTN)FvHeader + FvHeader->HeaderLength);
 | |
|   VariableStoreLength = NvStorageSize - FvHeader->HeaderLength;
 | |
|   ASSERT (sizeof (VARIABLE_STORE_HEADER) <= VariableStoreLength);
 | |
|   ASSERT (VariableStore->Size == VariableStoreLength);
 | |
| 
 | |
|   //
 | |
|   // Check if the Variable Store header is not corrupted
 | |
|   //
 | |
|   if (GetVariableStoreStatus (VariableStore) != EfiValid) {
 | |
|     FreePool (NvStorageData);
 | |
|     DEBUG ((DEBUG_ERROR, "Variable Store header is corrupted\n"));
 | |
|     return EFI_VOLUME_CORRUPTED;
 | |
|   }
 | |
| 
 | |
|   mNvFvHeaderCache = FvHeader;
 | |
| 
 | |
|   *VariableStoreBase = (EFI_PHYSICAL_ADDRESS)(UINTN)VariableStore;
 | |
| 
 | |
|   HwErrStorageSize                    = PcdGet32 (PcdHwErrStorageSize);
 | |
|   MaxUserNvVariableSpaceSize          = PcdGet32 (PcdMaxUserNvVariableSpaceSize);
 | |
|   BoottimeReservedNvVariableSpaceSize = PcdGet32 (PcdBoottimeReservedNvVariableSpaceSize);
 | |
| 
 | |
|   //
 | |
|   // Note that in EdkII variable driver implementation, Hardware Error Record type variable
 | |
|   // is stored with common variable in the same NV region. So the platform integrator should
 | |
|   // ensure that the value of PcdHwErrStorageSize is less than the value of
 | |
|   // (VariableStoreLength - sizeof (VARIABLE_STORE_HEADER)).
 | |
|   //
 | |
|   ASSERT (HwErrStorageSize < (VariableStoreLength - sizeof (VARIABLE_STORE_HEADER)));
 | |
|   //
 | |
|   // Ensure that the value of PcdMaxUserNvVariableSpaceSize is less than the value of
 | |
|   // (VariableStoreLength - sizeof (VARIABLE_STORE_HEADER)) - PcdGet32 (PcdHwErrStorageSize).
 | |
|   //
 | |
|   ASSERT (MaxUserNvVariableSpaceSize < (VariableStoreLength - sizeof (VARIABLE_STORE_HEADER) - HwErrStorageSize));
 | |
|   //
 | |
|   // Ensure that the value of PcdBoottimeReservedNvVariableSpaceSize is less than the value of
 | |
|   // (VariableStoreLength - sizeof (VARIABLE_STORE_HEADER)) - PcdGet32 (PcdHwErrStorageSize).
 | |
|   //
 | |
|   ASSERT (BoottimeReservedNvVariableSpaceSize < (VariableStoreLength - sizeof (VARIABLE_STORE_HEADER) - HwErrStorageSize));
 | |
| 
 | |
|   mVariableModuleGlobal->CommonVariableSpace        = ((UINTN)VariableStoreLength - sizeof (VARIABLE_STORE_HEADER) - HwErrStorageSize);
 | |
|   mVariableModuleGlobal->CommonMaxUserVariableSpace = ((MaxUserNvVariableSpaceSize != 0) ? MaxUserNvVariableSpaceSize : mVariableModuleGlobal->CommonVariableSpace);
 | |
|   mVariableModuleGlobal->CommonRuntimeVariableSpace = mVariableModuleGlobal->CommonVariableSpace - BoottimeReservedNvVariableSpaceSize;
 | |
| 
 | |
|   DEBUG ((
 | |
|     DEBUG_INFO,
 | |
|     "Variable driver common space: 0x%x 0x%x 0x%x\n",
 | |
|     mVariableModuleGlobal->CommonVariableSpace,
 | |
|     mVariableModuleGlobal->CommonMaxUserVariableSpace,
 | |
|     mVariableModuleGlobal->CommonRuntimeVariableSpace
 | |
|     ));
 | |
| 
 | |
|   //
 | |
|   // The max NV variable size should be < (VariableStoreLength - sizeof (VARIABLE_STORE_HEADER)).
 | |
|   //
 | |
|   ASSERT (GetNonVolatileMaxVariableSize () < (VariableStoreLength - sizeof (VARIABLE_STORE_HEADER)));
 | |
| 
 | |
|   return EFI_SUCCESS;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Init non-volatile variable store.
 | |
| 
 | |
|   @retval EFI_SUCCESS           Function successfully executed.
 | |
|   @retval EFI_OUT_OF_RESOURCES  Fail to allocate enough memory resource.
 | |
|   @retval EFI_VOLUME_CORRUPTED  Variable Store or Firmware Volume for Variable Store is corrupted.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| InitNonVolatileVariableStore (
 | |
|   VOID
 | |
|   )
 | |
| {
 | |
|   VARIABLE_HEADER       *Variable;
 | |
|   VARIABLE_HEADER       *NextVariable;
 | |
|   EFI_PHYSICAL_ADDRESS  VariableStoreBase;
 | |
|   UINTN                 VariableSize;
 | |
|   EFI_STATUS            Status;
 | |
| 
 | |
|   if (PcdGetBool (PcdEmuVariableNvModeEnable)) {
 | |
|     Status = InitEmuNonVolatileVariableStore (&VariableStoreBase);
 | |
|     if (EFI_ERROR (Status)) {
 | |
|       return Status;
 | |
|     }
 | |
| 
 | |
|     mVariableModuleGlobal->VariableGlobal.EmuNvMode = TRUE;
 | |
|     DEBUG ((DEBUG_INFO, "Variable driver will work at emulated non-volatile variable mode!\n"));
 | |
|   } else {
 | |
|     Status = InitRealNonVolatileVariableStore (&VariableStoreBase);
 | |
|     if (EFI_ERROR (Status)) {
 | |
|       return Status;
 | |
|     }
 | |
| 
 | |
|     mVariableModuleGlobal->VariableGlobal.EmuNvMode = FALSE;
 | |
|   }
 | |
| 
 | |
|   mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase = VariableStoreBase;
 | |
|   mNvVariableCache                                              = (VARIABLE_STORE_HEADER *)(UINTN)VariableStoreBase;
 | |
|   mVariableModuleGlobal->VariableGlobal.AuthFormat              = (BOOLEAN)(CompareGuid (&mNvVariableCache->Signature, &gEfiAuthenticatedVariableGuid));
 | |
| 
 | |
|   mVariableModuleGlobal->MaxVariableSize     = PcdGet32 (PcdMaxVariableSize);
 | |
|   mVariableModuleGlobal->MaxAuthVariableSize = ((PcdGet32 (PcdMaxAuthVariableSize) != 0) ? PcdGet32 (PcdMaxAuthVariableSize) : mVariableModuleGlobal->MaxVariableSize);
 | |
| 
 | |
|   //
 | |
|   // Parse non-volatile variable data and get last variable offset.
 | |
|   //
 | |
|   Variable = GetStartPointer (mNvVariableCache);
 | |
|   while (IsValidVariableHeader (Variable, GetEndPointer (mNvVariableCache))) {
 | |
|     NextVariable = GetNextVariablePtr (Variable, mVariableModuleGlobal->VariableGlobal.AuthFormat);
 | |
|     VariableSize = (UINTN)NextVariable - (UINTN)Variable;
 | |
|     if ((Variable->Attributes & (EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_HARDWARE_ERROR_RECORD)) == (EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_HARDWARE_ERROR_RECORD)) {
 | |
|       mVariableModuleGlobal->HwErrVariableTotalSize += VariableSize;
 | |
|     } else {
 | |
|       mVariableModuleGlobal->CommonVariableTotalSize += VariableSize;
 | |
|     }
 | |
| 
 | |
|     Variable = NextVariable;
 | |
|   }
 | |
| 
 | |
|   mVariableModuleGlobal->NonVolatileLastVariableOffset = (UINTN)Variable - (UINTN)mNvVariableCache;
 | |
| 
 | |
|   return EFI_SUCCESS;
 | |
| }
 |