2019-09-28 00:34:14 +02:00
/** @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 ) {
2021-12-05 23:54:02 +01:00
return MAX (
MAX ( PcdGet32 ( PcdMaxVariableSize ) , PcdGet32 ( PcdMaxAuthVariableSize ) ) ,
PcdGet32 ( PcdMaxHardwareErrorVariableSize )
) ;
2019-09-28 00:34:14 +02:00
} 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
)
{
2021-12-05 23:54:02 +01:00
VARIABLE_STORE_HEADER * VariableStore ;
UINT32 VariableStoreLength ;
BOOLEAN FullyInitializeStore ;
UINT32 HwErrStorageSize ;
2019-09-28 00:34:14 +02:00
FullyInitializeStore = TRUE ;
VariableStoreLength = PcdGet32 ( PcdVariableStoreSize ) ;
ASSERT ( sizeof ( VARIABLE_STORE_HEADER ) < = VariableStoreLength ) ;
//
// Allocate memory for variable store.
//
if ( PcdGet64 ( PcdEmuVariableNvStoreReserved ) = = 0 ) {
2021-12-05 23:54:02 +01:00
VariableStore = ( VARIABLE_STORE_HEADER * ) AllocateRuntimePool ( VariableStoreLength ) ;
2019-09-28 00:34:14 +02:00
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 =
2021-12-05 23:54:02 +01:00
( VARIABLE_STORE_HEADER * ) ( VOID * ) ( UINTN )
PcdGet64 ( PcdEmuVariableNvStoreReserved ) ;
2019-09-28 00:34:14 +02:00
if ( ( VariableStore - > Size = = VariableStoreLength ) & &
( CompareGuid ( & VariableStore - > Signature , & gEfiAuthenticatedVariableGuid ) | |
CompareGuid ( & VariableStore - > Signature , & gEfiVariableGuid ) ) & &
( VariableStore - > Format = = VARIABLE_STORE_FORMATTED ) & &
2021-12-05 23:54:02 +01:00
( VariableStore - > State = = VARIABLE_STORE_HEALTHY ) )
{
DEBUG ( (
2019-09-28 00:34:14 +02:00
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 ) ;
2021-12-05 23:54:02 +01:00
VariableStore - > Size = VariableStoreLength ;
VariableStore - > Format = VARIABLE_STORE_FORMATTED ;
VariableStore - > State = VARIABLE_STORE_HEALTHY ;
VariableStore - > Reserved = 0 ;
VariableStore - > Reserved1 = 0 ;
2019-09-28 00:34:14 +02:00
}
2021-12-05 23:54:02 +01:00
* VariableStoreBase = ( EFI_PHYSICAL_ADDRESS ) ( UINTN ) VariableStore ;
2019-09-28 00:34:14 +02:00
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 ) ) ) ;
2021-12-05 23:54:02 +01:00
mVariableModuleGlobal - > CommonVariableSpace = ( ( UINTN ) VariableStoreLength - sizeof ( VARIABLE_STORE_HEADER ) - HwErrStorageSize ) ;
2019-09-28 00:34:14 +02:00
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 (
2021-12-05 23:54:02 +01:00
OUT EFI_PHYSICAL_ADDRESS * VariableStoreBase
2019-09-28 00:34:14 +02:00
)
{
EFI_FIRMWARE_VOLUME_HEADER * FvHeader ;
VARIABLE_STORE_HEADER * VariableStore ;
UINT32 VariableStoreLength ;
EFI_HOB_GUID_TYPE * GuidHob ;
EFI_PHYSICAL_ADDRESS NvStorageBase ;
UINT8 * NvStorageData ;
UINT32 NvStorageSize ;
2022-04-06 03:34:51 +02:00
UINT64 NvStorageSize64 ;
2019-09-28 00:34:14 +02:00
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 ;
2022-04-06 03:34:51 +02:00
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 ) ;
2019-09-28 00:34:14 +02:00
//
// 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.
//
2021-12-05 23:54:02 +01:00
CopyMem ( NvStorageData , ( UINT8 * ) ( UINTN ) NvStorageBase , NvStorageSize ) ;
2019-09-28 00:34:14 +02:00
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 ) {
2021-12-05 23:54:02 +01:00
FtwLastWriteData = ( FAULT_TOLERANT_WRITE_LAST_WRITE_DATA * ) GET_GUID_HOB_DATA ( GuidHob ) ;
2019-09-28 00:34:14 +02:00
if ( FtwLastWriteData - > TargetAddress = = NvStorageBase ) {
2021-12-05 23:54:02 +01:00
DEBUG ( ( DEBUG_INFO , " Variable: NV storage is backed up in spare block: 0x%x \n " , ( UINTN ) FtwLastWriteData - > SpareAddress ) ) ;
2019-09-28 00:34:14 +02:00
//
// Copy the backed up NV storage data to the memory buffer from spare block.
//
2021-12-05 23:54:02 +01:00
CopyMem ( NvStorageData , ( UINT8 * ) ( UINTN ) ( FtwLastWriteData - > SpareAddress ) , NvStorageSize ) ;
2019-09-28 00:34:14 +02:00
} else if ( ( FtwLastWriteData - > TargetAddress > NvStorageBase ) & &
2021-12-05 23:54:02 +01:00
( FtwLastWriteData - > TargetAddress < ( NvStorageBase + NvStorageSize ) ) )
{
2019-09-28 00:34:14 +02:00
//
// Flash NV storage from the Offset is backed up in spare block.
//
2021-12-05 23:54:02 +01:00
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 ) ) ;
2019-09-28 00:34:14 +02:00
//
// Copy the partial backed up NV storage data to the memory buffer from spare block.
//
2021-12-05 23:54:02 +01:00
CopyMem ( NvStorageData + BackUpOffset , ( UINT8 * ) ( UINTN ) FtwLastWriteData - > SpareAddress , BackUpSize ) ;
2019-09-28 00:34:14 +02:00
}
}
}
2021-12-05 23:54:02 +01:00
FvHeader = ( EFI_FIRMWARE_VOLUME_HEADER * ) NvStorageData ;
2019-09-28 00:34:14 +02:00
//
// 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 ;
}
2021-12-05 23:54:02 +01:00
VariableStore = ( VARIABLE_STORE_HEADER * ) ( ( UINTN ) FvHeader + FvHeader - > HeaderLength ) ;
2019-09-28 00:34:14 +02:00
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 ) ;
2021-12-05 23:54:02 +01:00
DEBUG ( ( DEBUG_ERROR , " Variable Store header is corrupted \n " ) ) ;
2019-09-28 00:34:14 +02:00
return EFI_VOLUME_CORRUPTED ;
}
mNvFvHeaderCache = FvHeader ;
2021-12-05 23:54:02 +01:00
* VariableStoreBase = ( EFI_PHYSICAL_ADDRESS ) ( UINTN ) VariableStore ;
2019-09-28 00:34:14 +02:00
2021-12-05 23:54:02 +01:00
HwErrStorageSize = PcdGet32 ( PcdHwErrStorageSize ) ;
MaxUserNvVariableSpaceSize = PcdGet32 ( PcdMaxUserNvVariableSpaceSize ) ;
2019-09-28 00:34:14 +02:00
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 ) ) ;
2021-12-05 23:54:02 +01:00
mVariableModuleGlobal - > CommonVariableSpace = ( ( UINTN ) VariableStoreLength - sizeof ( VARIABLE_STORE_HEADER ) - HwErrStorageSize ) ;
2019-09-28 00:34:14 +02:00
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
)
{
2021-12-05 23:54:02 +01:00
VARIABLE_HEADER * Variable ;
VARIABLE_HEADER * NextVariable ;
EFI_PHYSICAL_ADDRESS VariableStoreBase ;
UINTN VariableSize ;
EFI_STATUS Status ;
2019-09-28 00:34:14 +02:00
if ( PcdGetBool ( PcdEmuVariableNvModeEnable ) ) {
Status = InitEmuNonVolatileVariableStore ( & VariableStoreBase ) ;
if ( EFI_ERROR ( Status ) ) {
return Status ;
}
2021-12-05 23:54:02 +01:00
2019-09-28 00:34:14 +02:00
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 ;
}
2021-12-05 23:54:02 +01:00
2019-09-28 00:34:14 +02:00
mVariableModuleGlobal - > VariableGlobal . EmuNvMode = FALSE ;
}
mVariableModuleGlobal - > VariableGlobal . NonVolatileVariableBase = VariableStoreBase ;
2021-12-05 23:54:02 +01:00
mNvVariableCache = ( VARIABLE_STORE_HEADER * ) ( UINTN ) VariableStoreBase ;
mVariableModuleGlobal - > VariableGlobal . AuthFormat = ( BOOLEAN ) ( CompareGuid ( & mNvVariableCache - > Signature , & gEfiAuthenticatedVariableGuid ) ) ;
2019-09-28 00:34:14 +02:00
2021-12-05 23:54:02 +01:00
mVariableModuleGlobal - > MaxVariableSize = PcdGet32 ( PcdMaxVariableSize ) ;
2019-09-28 00:34:14 +02:00
mVariableModuleGlobal - > MaxAuthVariableSize = ( ( PcdGet32 ( PcdMaxAuthVariableSize ) ! = 0 ) ? PcdGet32 ( PcdMaxAuthVariableSize ) : mVariableModuleGlobal - > MaxVariableSize ) ;
//
// Parse non-volatile variable data and get last variable offset.
//
2021-12-05 23:54:02 +01:00
Variable = GetStartPointer ( mNvVariableCache ) ;
2019-09-28 00:34:14 +02:00
while ( IsValidVariableHeader ( Variable , GetEndPointer ( mNvVariableCache ) ) ) {
NextVariable = GetNextVariablePtr ( Variable , mVariableModuleGlobal - > VariableGlobal . AuthFormat ) ;
2021-12-05 23:54:02 +01:00
VariableSize = ( UINTN ) NextVariable - ( UINTN ) Variable ;
2019-09-28 00:34:14 +02:00
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 ;
}
2021-12-05 23:54:02 +01:00
mVariableModuleGlobal - > NonVolatileLastVariableOffset = ( UINTN ) Variable - ( UINTN ) mNvVariableCache ;
2019-09-28 00:34:14 +02:00
return EFI_SUCCESS ;
}