2011-09-02 09:49:32 +02:00
/** @file
2011-10-28 11:55:09 +02:00
The common variable operation routines shared by DXE_RINTIME variable
2011-09-02 09:49:32 +02:00
module and DXE_SMM variable module .
Copyright ( c ) 2009 - 2011 , Intel Corporation . All rights reserved . < BR >
2011-10-28 11:55:09 +02:00
This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License
which accompanies this distribution . The full text of the license may be found at
2011-09-02 09:49:32 +02:00
http : //opensource.org/licenses/bsd-license.php
2011-10-28 11:55:09 +02:00
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN " AS IS " BASIS ,
2011-09-02 09:49:32 +02:00
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND , EITHER EXPRESS OR IMPLIED .
* */
# include "Variable.h"
# include "AuthService.h"
VARIABLE_MODULE_GLOBAL * mVariableModuleGlobal ;
///
/// Define a memory cache that improves the search performance for a variable.
///
VARIABLE_STORE_HEADER * mNvVariableCache = NULL ;
///
/// The memory entry used for variable statistics data.
///
VARIABLE_INFO_ENTRY * gVariableInfo = NULL ;
/**
2011-10-28 11:55:09 +02:00
Routine used to track statistical information about variable usage .
2011-09-02 09:49:32 +02:00
The data is stored in the EFI system table so it can be accessed later .
2011-10-28 11:55:09 +02:00
VariableInfo . efi can dump out the table . Only Boot Services variable
2011-09-02 09:49:32 +02:00
accesses are tracked by this code . The PcdVariableCollectStatistics
2011-10-28 11:55:09 +02:00
build flag controls if this feature is enabled .
2011-09-02 09:49:32 +02:00
2011-10-28 11:55:09 +02:00
A read that hits in the cache will have Read and Cache true for
2011-09-02 09:49:32 +02:00
the transaction . Data is allocated by this routine , but never
freed .
@ param [ in ] VariableName Name of the Variable to track .
@ param [ in ] VendorGuid Guid of the Variable to track .
@ param [ in ] Volatile TRUE if volatile FALSE if non - volatile .
@ param [ in ] Read TRUE if GetVariable ( ) was called .
@ param [ in ] Write TRUE if SetVariable ( ) was called .
@ param [ in ] Delete TRUE if deleted via SetVariable ( ) .
@ param [ in ] Cache TRUE for a cache hit .
* */
VOID
UpdateVariableInfo (
IN CHAR16 * VariableName ,
IN EFI_GUID * VendorGuid ,
IN BOOLEAN Volatile ,
IN BOOLEAN Read ,
IN BOOLEAN Write ,
IN BOOLEAN Delete ,
IN BOOLEAN Cache
)
{
VARIABLE_INFO_ENTRY * Entry ;
if ( FeaturePcdGet ( PcdVariableCollectStatistics ) ) {
if ( AtRuntime ( ) ) {
// Don't collect statistics at runtime.
return ;
}
if ( gVariableInfo = = NULL ) {
//
// On the first call allocate a entry and place a pointer to it in
// the EFI System Table.
//
gVariableInfo = AllocateZeroPool ( sizeof ( VARIABLE_INFO_ENTRY ) ) ;
ASSERT ( gVariableInfo ! = NULL ) ;
CopyGuid ( & gVariableInfo - > VendorGuid , VendorGuid ) ;
gVariableInfo - > Name = AllocatePool ( StrSize ( VariableName ) ) ;
ASSERT ( gVariableInfo - > Name ! = NULL ) ;
StrCpy ( gVariableInfo - > Name , VariableName ) ;
gVariableInfo - > Volatile = Volatile ;
}
2011-10-28 11:55:09 +02:00
2011-09-02 09:49:32 +02:00
for ( Entry = gVariableInfo ; Entry ! = NULL ; Entry = Entry - > Next ) {
if ( CompareGuid ( VendorGuid , & Entry - > VendorGuid ) ) {
if ( StrCmp ( VariableName , Entry - > Name ) = = 0 ) {
if ( Read ) {
Entry - > ReadCount + + ;
}
if ( Write ) {
Entry - > WriteCount + + ;
}
if ( Delete ) {
Entry - > DeleteCount + + ;
}
if ( Cache ) {
Entry - > CacheCount + + ;
}
return ;
}
}
if ( Entry - > Next = = NULL ) {
//
// If the entry is not in the table add it.
// Next iteration of the loop will fill in the data.
//
Entry - > Next = AllocateZeroPool ( sizeof ( VARIABLE_INFO_ENTRY ) ) ;
ASSERT ( Entry - > Next ! = NULL ) ;
CopyGuid ( & Entry - > Next - > VendorGuid , VendorGuid ) ;
Entry - > Next - > Name = AllocatePool ( StrSize ( VariableName ) ) ;
ASSERT ( Entry - > Next - > Name ! = NULL ) ;
StrCpy ( Entry - > Next - > Name , VariableName ) ;
Entry - > Next - > Volatile = Volatile ;
}
}
}
}
/**
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 function writes data to the FWH at the correct LBA even if the LBAs
are fragmented .
@ param Global Pointer to VARAIBLE_GLOBAL structure .
@ param Volatile Point out the Variable is Volatile or Non - Volatile .
@ param SetByIndex TRUE if target pointer is given as index .
FALSE if target pointer is absolute .
@ param Fvb Pointer to the writable FVB protocol .
@ param DataPtrIndex Pointer to the Data from the end of VARIABLE_STORE_HEADER
structure .
@ param DataSize Size of data to be written .
@ param Buffer Pointer to the buffer from which data is written .
@ retval EFI_INVALID_PARAMETER Parameters not valid .
@ retval EFI_SUCCESS Variable store successfully updated .
* */
EFI_STATUS
UpdateVariableStore (
IN VARIABLE_GLOBAL * Global ,
IN BOOLEAN Volatile ,
IN BOOLEAN SetByIndex ,
IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL * Fvb ,
IN UINTN DataPtrIndex ,
IN UINT32 DataSize ,
IN UINT8 * Buffer
)
{
EFI_FV_BLOCK_MAP_ENTRY * PtrBlockMapEntry ;
UINTN BlockIndex2 ;
UINTN LinearOffset ;
UINTN CurrWriteSize ;
UINTN CurrWritePtr ;
UINT8 * CurrBuffer ;
EFI_LBA LbaNumber ;
UINTN Size ;
EFI_FIRMWARE_VOLUME_HEADER * FwVolHeader ;
VARIABLE_STORE_HEADER * VolatileBase ;
EFI_PHYSICAL_ADDRESS FvVolHdr ;
EFI_PHYSICAL_ADDRESS DataPtr ;
EFI_STATUS Status ;
FwVolHeader = NULL ;
DataPtr = DataPtrIndex ;
//
// Check if the Data is Volatile.
//
if ( ! Volatile ) {
2011-09-21 07:17:50 +02:00
if ( Fvb = = NULL ) {
return EFI_INVALID_PARAMETER ;
}
2011-09-02 09:49:32 +02:00
Status = Fvb - > GetPhysicalAddress ( Fvb , & FvVolHdr ) ;
ASSERT_EFI_ERROR ( Status ) ;
FwVolHeader = ( EFI_FIRMWARE_VOLUME_HEADER * ) ( ( UINTN ) FvVolHdr ) ;
//
// Data Pointer should point to the actual Address where data is to be
// written.
//
if ( SetByIndex ) {
DataPtr + = mVariableModuleGlobal - > VariableGlobal . NonVolatileVariableBase ;
}
if ( ( DataPtr + DataSize ) > = ( ( EFI_PHYSICAL_ADDRESS ) ( UINTN ) ( ( UINT8 * ) FwVolHeader + FwVolHeader - > FvLength ) ) ) {
return EFI_INVALID_PARAMETER ;
}
} else {
//
// Data Pointer should point to the actual Address where data is to be
// written.
//
VolatileBase = ( VARIABLE_STORE_HEADER * ) ( ( UINTN ) mVariableModuleGlobal - > VariableGlobal . VolatileVariableBase ) ;
if ( SetByIndex ) {
DataPtr + = mVariableModuleGlobal - > VariableGlobal . VolatileVariableBase ;
}
if ( ( DataPtr + DataSize ) > = ( ( UINTN ) ( ( UINT8 * ) VolatileBase + VolatileBase - > Size ) ) ) {
return EFI_INVALID_PARAMETER ;
}
2011-10-28 11:55:09 +02:00
2011-09-02 09:49:32 +02:00
//
// If Volatile Variable just do a simple mem copy.
2011-10-28 11:55:09 +02:00
//
2011-09-02 09:49:32 +02:00
CopyMem ( ( UINT8 * ) ( UINTN ) DataPtr , Buffer , DataSize ) ;
return EFI_SUCCESS ;
}
2011-10-28 11:55:09 +02:00
2011-09-02 09:49:32 +02:00
//
// If we are here we are dealing with Non-Volatile Variables.
//
LinearOffset = ( UINTN ) FwVolHeader ;
CurrWritePtr = ( UINTN ) DataPtr ;
CurrWriteSize = DataSize ;
CurrBuffer = Buffer ;
LbaNumber = 0 ;
if ( CurrWritePtr < LinearOffset ) {
return EFI_INVALID_PARAMETER ;
}
for ( PtrBlockMapEntry = FwVolHeader - > BlockMap ; PtrBlockMapEntry - > NumBlocks ! = 0 ; PtrBlockMapEntry + + ) {
for ( BlockIndex2 = 0 ; BlockIndex2 < PtrBlockMapEntry - > NumBlocks ; BlockIndex2 + + ) {
//
// Check to see if the Variable Writes are spanning through multiple
// blocks.
//
if ( ( CurrWritePtr > = LinearOffset ) & & ( CurrWritePtr < LinearOffset + PtrBlockMapEntry - > Length ) ) {
if ( ( CurrWritePtr + CurrWriteSize ) < = ( LinearOffset + PtrBlockMapEntry - > Length ) ) {
Status = Fvb - > Write (
Fvb ,
LbaNumber ,
( UINTN ) ( CurrWritePtr - LinearOffset ) ,
& CurrWriteSize ,
CurrBuffer
) ;
return Status ;
} else {
Size = ( UINT32 ) ( LinearOffset + PtrBlockMapEntry - > Length - CurrWritePtr ) ;
Status = Fvb - > Write (
Fvb ,
LbaNumber ,
( UINTN ) ( CurrWritePtr - LinearOffset ) ,
& Size ,
CurrBuffer
) ;
if ( EFI_ERROR ( Status ) ) {
return Status ;
}
CurrWritePtr = LinearOffset + PtrBlockMapEntry - > Length ;
CurrBuffer = CurrBuffer + Size ;
CurrWriteSize = CurrWriteSize - Size ;
}
}
LinearOffset + = PtrBlockMapEntry - > Length ;
LbaNumber + + ;
}
}
return EFI_SUCCESS ;
}
/**
This code gets the current status of Variable Store .
@ param VarStoreHeader Pointer to the Variable Store Header .
@ retval EfiRaw Variable store status is raw .
@ retval EfiValid Variable store status is valid .
@ retval EfiInvalid Variable store status is invalid .
* */
VARIABLE_STORE_STATUS
GetVariableStoreStatus (
IN VARIABLE_STORE_HEADER * VarStoreHeader
)
{
if ( CompareGuid ( & VarStoreHeader - > Signature , & gEfiAuthenticatedVariableGuid ) & &
VarStoreHeader - > Format = = VARIABLE_STORE_FORMATTED & &
VarStoreHeader - > State = = VARIABLE_STORE_HEALTHY
) {
return EfiValid ;
} else 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 ;
}
}
/**
This code gets the size of name of variable .
@ param Variable Pointer to the Variable Header .
@ return UINTN Size of variable in bytes .
* */
UINTN
NameSizeOfVariable (
IN VARIABLE_HEADER * Variable
)
{
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 variable data .
@ param Variable Pointer to the Variable Header .
@ return Size of variable in bytes .
* */
UINTN
DataSizeOfVariable (
IN VARIABLE_HEADER * Variable
)
{
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 .
@ return Pointer to Variable Name which is Unicode encoding .
* */
CHAR16 *
GetVariableNamePtr (
IN VARIABLE_HEADER * Variable
)
{
return ( CHAR16 * ) ( Variable + 1 ) ;
}
/**
This code gets the pointer to the variable data .
@ param Variable Pointer to the Variable Header .
@ return Pointer to Variable Data .
* */
UINT8 *
GetVariableDataPtr (
IN VARIABLE_HEADER * Variable
)
{
UINTN Value ;
2011-10-28 11:55:09 +02:00
2011-09-02 09:49:32 +02:00
//
// Be careful about pad size for alignment.
//
Value = ( UINTN ) GetVariableNamePtr ( Variable ) ;
Value + = NameSizeOfVariable ( Variable ) ;
Value + = GET_PAD_SIZE ( NameSizeOfVariable ( Variable ) ) ;
return ( UINT8 * ) Value ;
}
/**
This code gets the pointer to the next variable header .
@ param Variable Pointer to the Variable Header .
@ return Pointer to next variable header .
* */
VARIABLE_HEADER *
GetNextVariablePtr (
IN VARIABLE_HEADER * Variable
)
{
UINTN Value ;
if ( ! IsValidVariableHeader ( Variable ) ) {
return NULL ;
}
Value = ( UINTN ) GetVariableDataPtr ( Variable ) ;
Value + = DataSizeOfVariable ( Variable ) ;
Value + = GET_PAD_SIZE ( DataSizeOfVariable ( Variable ) ) ;
//
// Be careful about pad size for alignment.
//
return ( VARIABLE_HEADER * ) HEADER_ALIGN ( Value ) ;
}
/**
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 end 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 .
2011-10-28 11:55:09 +02:00
@ return Pointer to the end of the variable storage area .
2011-09-02 09:49:32 +02:00
* */
VARIABLE_HEADER *
GetEndPointer (
IN VARIABLE_STORE_HEADER * VarStoreHeader
)
{
//
// The end of variable store
//
return ( VARIABLE_HEADER * ) HEADER_ALIGN ( ( UINTN ) VarStoreHeader + VarStoreHeader - > Size ) ;
}
/**
Variable store garbage collection and reclaim operation .
@ param VariableBase Base address of variable store .
@ param LastVariableOffset Offset of last variable .
@ param IsVolatile The variable store is volatile or not ;
if it is non - volatile , need FTW .
@ param UpdatingVariable Pointer to updating variable .
@ return EFI_OUT_OF_RESOURCES
@ return EFI_SUCCESS
@ return Others
* */
EFI_STATUS
Reclaim (
IN EFI_PHYSICAL_ADDRESS VariableBase ,
OUT UINTN * LastVariableOffset ,
IN BOOLEAN IsVolatile ,
IN VARIABLE_HEADER * UpdatingVariable
)
{
VARIABLE_HEADER * Variable ;
VARIABLE_HEADER * AddedVariable ;
VARIABLE_HEADER * NextVariable ;
VARIABLE_HEADER * NextAddedVariable ;
VARIABLE_STORE_HEADER * VariableStoreHeader ;
UINT8 * ValidBuffer ;
UINTN MaximumBufferSize ;
UINTN VariableSize ;
UINTN VariableNameSize ;
UINTN UpdatingVariableNameSize ;
UINTN NameSize ;
UINT8 * CurrPtr ;
VOID * Point0 ;
VOID * Point1 ;
BOOLEAN FoundAdded ;
EFI_STATUS Status ;
CHAR16 * VariableNamePtr ;
CHAR16 * UpdatingVariableNamePtr ;
VariableStoreHeader = ( VARIABLE_STORE_HEADER * ) ( ( UINTN ) VariableBase ) ;
//
// Recalculate the total size of Common/HwErr type variables in non-volatile area.
//
if ( ! IsVolatile ) {
mVariableModuleGlobal - > CommonVariableTotalSize = 0 ;
mVariableModuleGlobal - > HwErrVariableTotalSize = 0 ;
}
//
// Start Pointers for the variable.
//
Variable = GetStartPointer ( VariableStoreHeader ) ;
MaximumBufferSize = sizeof ( VARIABLE_STORE_HEADER ) ;
while ( IsValidVariableHeader ( Variable ) ) {
NextVariable = GetNextVariablePtr ( Variable ) ;
2011-10-28 11:55:09 +02:00
if ( Variable - > State = = VAR_ADDED | |
2011-09-02 09:49:32 +02:00
Variable - > State = = ( VAR_IN_DELETED_TRANSITION & VAR_ADDED )
) {
VariableSize = ( UINTN ) NextVariable - ( UINTN ) Variable ;
MaximumBufferSize + = VariableSize ;
}
Variable = NextVariable ;
}
//
2011-10-28 11:55:09 +02:00
// Reserve the 1 Bytes with Oxff to identify the
// end of the variable buffer.
//
2011-09-02 09:49:32 +02:00
MaximumBufferSize + = 1 ;
ValidBuffer = AllocatePool ( MaximumBufferSize ) ;
if ( ValidBuffer = = NULL ) {
return EFI_OUT_OF_RESOURCES ;
}
SetMem ( ValidBuffer , MaximumBufferSize , 0xff ) ;
//
// Copy variable store header.
//
CopyMem ( ValidBuffer , VariableStoreHeader , sizeof ( VARIABLE_STORE_HEADER ) ) ;
CurrPtr = ( UINT8 * ) GetStartPointer ( ( VARIABLE_STORE_HEADER * ) ValidBuffer ) ;
//
// Reinstall all ADDED variables as long as they are not identical to Updating Variable.
2011-10-28 11:55:09 +02:00
//
2011-09-02 09:49:32 +02:00
Variable = GetStartPointer ( VariableStoreHeader ) ;
while ( IsValidVariableHeader ( Variable ) ) {
NextVariable = GetNextVariablePtr ( Variable ) ;
if ( Variable - > State = = VAR_ADDED ) {
if ( UpdatingVariable ! = NULL ) {
if ( UpdatingVariable = = Variable ) {
Variable = NextVariable ;
continue ;
}
VariableNameSize = NameSizeOfVariable ( Variable ) ;
UpdatingVariableNameSize = NameSizeOfVariable ( UpdatingVariable ) ;
VariableNamePtr = GetVariableNamePtr ( Variable ) ;
UpdatingVariableNamePtr = GetVariableNamePtr ( UpdatingVariable ) ;
if ( CompareGuid ( & Variable - > VendorGuid , & UpdatingVariable - > VendorGuid ) & &
VariableNameSize = = UpdatingVariableNameSize & &
CompareMem ( VariableNamePtr , UpdatingVariableNamePtr , VariableNameSize ) = = 0 ) {
Variable = NextVariable ;
continue ;
}
}
VariableSize = ( UINTN ) NextVariable - ( UINTN ) Variable ;
CopyMem ( CurrPtr , ( UINT8 * ) Variable , VariableSize ) ;
CurrPtr + = VariableSize ;
if ( ( ! IsVolatile ) & & ( ( Variable - > Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD ) = = EFI_VARIABLE_HARDWARE_ERROR_RECORD ) ) {
mVariableModuleGlobal - > HwErrVariableTotalSize + = VariableSize ;
} else if ( ( ! IsVolatile ) & & ( ( Variable - > Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD ) ! = EFI_VARIABLE_HARDWARE_ERROR_RECORD ) ) {
mVariableModuleGlobal - > CommonVariableTotalSize + = VariableSize ;
}
}
Variable = NextVariable ;
}
//
// Reinstall the variable being updated if it is not NULL.
//
if ( UpdatingVariable ! = NULL ) {
VariableSize = ( UINTN ) ( GetNextVariablePtr ( UpdatingVariable ) ) - ( UINTN ) UpdatingVariable ;
CopyMem ( CurrPtr , ( UINT8 * ) UpdatingVariable , VariableSize ) ;
CurrPtr + = VariableSize ;
if ( ( ! IsVolatile ) & & ( ( UpdatingVariable - > Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD ) = = EFI_VARIABLE_HARDWARE_ERROR_RECORD ) ) {
mVariableModuleGlobal - > HwErrVariableTotalSize + = VariableSize ;
} else if ( ( ! IsVolatile ) & & ( ( UpdatingVariable - > Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD ) ! = EFI_VARIABLE_HARDWARE_ERROR_RECORD ) ) {
mVariableModuleGlobal - > CommonVariableTotalSize + = VariableSize ;
}
}
//
// Reinstall all in delete transition variables.
2011-10-28 11:55:09 +02:00
//
2011-09-02 09:49:32 +02:00
Variable = GetStartPointer ( VariableStoreHeader ) ;
while ( IsValidVariableHeader ( Variable ) ) {
NextVariable = GetNextVariablePtr ( Variable ) ;
if ( Variable ! = UpdatingVariable & & Variable - > State = = ( VAR_IN_DELETED_TRANSITION & VAR_ADDED ) ) {
//
2011-10-28 11:55:09 +02:00
// Buffer has cached all ADDED variable.
2011-09-02 09:49:32 +02:00
// Per IN_DELETED variable, we have to guarantee that
2011-10-28 11:55:09 +02:00
// no ADDED one in previous buffer.
//
2011-09-02 09:49:32 +02:00
FoundAdded = FALSE ;
AddedVariable = GetStartPointer ( ( VARIABLE_STORE_HEADER * ) ValidBuffer ) ;
while ( IsValidVariableHeader ( AddedVariable ) ) {
NextAddedVariable = GetNextVariablePtr ( AddedVariable ) ;
NameSize = NameSizeOfVariable ( AddedVariable ) ;
if ( CompareGuid ( & AddedVariable - > VendorGuid , & Variable - > VendorGuid ) & &
NameSize = = NameSizeOfVariable ( Variable )
) {
Point0 = ( VOID * ) GetVariableNamePtr ( AddedVariable ) ;
Point1 = ( VOID * ) GetVariableNamePtr ( Variable ) ;
if ( CompareMem ( Point0 , Point1 , NameSizeOfVariable ( AddedVariable ) ) = = 0 ) {
FoundAdded = TRUE ;
break ;
}
}
AddedVariable = NextAddedVariable ;
}
if ( ! FoundAdded ) {
//
// Promote VAR_IN_DELETED_TRANSITION to VAR_ADDED.
//
VariableSize = ( UINTN ) NextVariable - ( UINTN ) Variable ;
CopyMem ( CurrPtr , ( UINT8 * ) Variable , VariableSize ) ;
( ( VARIABLE_HEADER * ) CurrPtr ) - > State = VAR_ADDED ;
CurrPtr + = VariableSize ;
if ( ( ! IsVolatile ) & & ( ( Variable - > Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD ) = = EFI_VARIABLE_HARDWARE_ERROR_RECORD ) ) {
mVariableModuleGlobal - > HwErrVariableTotalSize + = VariableSize ;
} else if ( ( ! IsVolatile ) & & ( ( Variable - > Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD ) ! = EFI_VARIABLE_HARDWARE_ERROR_RECORD ) ) {
mVariableModuleGlobal - > CommonVariableTotalSize + = VariableSize ;
}
}
}
Variable = NextVariable ;
}
if ( IsVolatile ) {
//
// If volatile variable store, just copy valid buffer.
//
SetMem ( ( UINT8 * ) ( UINTN ) VariableBase , VariableStoreHeader - > Size , 0xff ) ;
CopyMem ( ( UINT8 * ) ( UINTN ) VariableBase , ValidBuffer , ( UINTN ) ( CurrPtr - ( UINT8 * ) ValidBuffer ) ) ;
Status = EFI_SUCCESS ;
} else {
//
// If non-volatile variable store, perform FTW here.
//
Status = FtwVariableSpace (
VariableBase ,
ValidBuffer ,
( UINTN ) ( CurrPtr - ( UINT8 * ) ValidBuffer )
) ;
CopyMem ( mNvVariableCache , ( CHAR8 * ) ( UINTN ) VariableBase , VariableStoreHeader - > Size ) ;
}
if ( ! EFI_ERROR ( Status ) ) {
* LastVariableOffset = ( UINTN ) ( CurrPtr - ( UINT8 * ) ValidBuffer ) ;
} else {
* LastVariableOffset = 0 ;
}
FreePool ( ValidBuffer ) ;
return Status ;
}
2011-10-19 14:40:52 +02:00
/**
Find the variable in the specified variable store .
@ param VariableName Name of the variable to be found
@ param VendorGuid Vendor GUID to be found .
@ param PtrTrack Variable Track Pointer structure that contains Variable Information .
@ retval EFI_SUCCESS Variable found successfully
@ retval EFI_NOT_FOUND Variable not found
* */
EFI_STATUS
FindVariableEx (
IN CHAR16 * VariableName ,
IN EFI_GUID * VendorGuid ,
IN OUT VARIABLE_POINTER_TRACK * PtrTrack
)
{
VARIABLE_HEADER * InDeletedVariable ;
VOID * Point ;
//
// Find the variable by walk through HOB, volatile and non-volatile variable store.
//
InDeletedVariable = NULL ;
for ( PtrTrack - > CurrPtr = PtrTrack - > StartPtr
; ( PtrTrack - > CurrPtr < PtrTrack - > EndPtr ) & & IsValidVariableHeader ( PtrTrack - > CurrPtr )
; PtrTrack - > CurrPtr = GetNextVariablePtr ( PtrTrack - > CurrPtr )
) {
2011-10-28 11:55:09 +02:00
if ( PtrTrack - > CurrPtr - > State = = VAR_ADDED | |
2011-10-19 14:40:52 +02:00
PtrTrack - > CurrPtr - > State = = ( VAR_IN_DELETED_TRANSITION & VAR_ADDED )
) {
if ( ! AtRuntime ( ) | | ( ( PtrTrack - > CurrPtr - > Attributes & EFI_VARIABLE_RUNTIME_ACCESS ) ! = 0 ) ) {
if ( VariableName [ 0 ] = = 0 ) {
if ( PtrTrack - > CurrPtr - > State = = ( VAR_IN_DELETED_TRANSITION & VAR_ADDED ) ) {
InDeletedVariable = PtrTrack - > CurrPtr ;
} else {
return EFI_SUCCESS ;
}
} else {
if ( CompareGuid ( VendorGuid , & PtrTrack - > CurrPtr - > VendorGuid ) ) {
Point = ( VOID * ) GetVariableNamePtr ( PtrTrack - > CurrPtr ) ;
ASSERT ( NameSizeOfVariable ( PtrTrack - > CurrPtr ) ! = 0 ) ;
if ( CompareMem ( VariableName , Point , NameSizeOfVariable ( PtrTrack - > CurrPtr ) ) = = 0 ) {
if ( PtrTrack - > CurrPtr - > State = = ( VAR_IN_DELETED_TRANSITION & VAR_ADDED ) ) {
InDeletedVariable = PtrTrack - > CurrPtr ;
} else {
return EFI_SUCCESS ;
}
}
}
}
}
}
}
PtrTrack - > CurrPtr = InDeletedVariable ;
return ( PtrTrack - > CurrPtr = = NULL ) ? EFI_NOT_FOUND : EFI_SUCCESS ;
}
2011-09-02 09:49:32 +02:00
/**
Finds variable in storage blocks of volatile and non - volatile storage areas .
This code finds variable in storage blocks of volatile and non - volatile storage areas .
If VariableName is an empty string , then we just return the first
qualified variable without comparing VariableName and VendorGuid .
Otherwise , VariableName and VendorGuid are compared .
@ param VariableName Name of the variable to be found .
@ param VendorGuid Vendor GUID to be found .
@ param PtrTrack VARIABLE_POINTER_TRACK structure for output ,
including the range searched and the target position .
@ param Global Pointer to VARIABLE_GLOBAL structure , including
base of volatile variable storage area , base of
NV variable storage area , and a lock .
@ retval EFI_INVALID_PARAMETER If VariableName is not an empty string , while
VendorGuid is NULL .
@ retval EFI_SUCCESS Variable successfully found .
@ retval EFI_NOT_FOUND Variable not found
* */
EFI_STATUS
FindVariable (
IN CHAR16 * VariableName ,
IN EFI_GUID * VendorGuid ,
OUT VARIABLE_POINTER_TRACK * PtrTrack ,
IN VARIABLE_GLOBAL * Global
)
{
2011-10-19 14:40:52 +02:00
EFI_STATUS Status ;
VARIABLE_STORE_HEADER * VariableStoreHeader [ VariableStoreTypeMax ] ;
VARIABLE_STORE_TYPE Type ;
if ( VariableName [ 0 ] ! = 0 & & VendorGuid = = NULL ) {
return EFI_INVALID_PARAMETER ;
}
2011-09-02 09:49:32 +02:00
//
2011-10-19 14:40:52 +02:00
// 0: Volatile, 1: HOB, 2: Non-Volatile.
2011-09-02 09:49:32 +02:00
// The index and attributes mapping must be kept in this order as RuntimeServiceGetNextVariableName
// make use of this mapping to implement search algorithm.
//
2011-10-19 14:40:52 +02:00
VariableStoreHeader [ VariableStoreTypeVolatile ] = ( VARIABLE_STORE_HEADER * ) ( UINTN ) Global - > VolatileVariableBase ;
VariableStoreHeader [ VariableStoreTypeHob ] = ( VARIABLE_STORE_HEADER * ) ( UINTN ) Global - > HobVariableBase ;
VariableStoreHeader [ VariableStoreTypeNv ] = mNvVariableCache ;
2011-09-02 09:49:32 +02:00
//
2011-10-19 14:40:52 +02:00
// Find the variable by walk through HOB, volatile and non-volatile variable store.
2011-09-02 09:49:32 +02:00
//
2011-10-19 14:40:52 +02:00
for ( Type = ( VARIABLE_STORE_TYPE ) 0 ; Type < VariableStoreTypeMax ; Type + + ) {
if ( VariableStoreHeader [ Type ] = = NULL ) {
continue ;
}
2011-09-02 09:49:32 +02:00
2011-10-19 14:40:52 +02:00
PtrTrack - > StartPtr = GetStartPointer ( VariableStoreHeader [ Type ] ) ;
PtrTrack - > EndPtr = GetEndPointer ( VariableStoreHeader [ Type ] ) ;
PtrTrack - > Volatile = ( BOOLEAN ) ( Type = = VariableStoreTypeVolatile ) ;
2011-09-02 09:49:32 +02:00
2011-10-19 14:40:52 +02:00
Status = FindVariableEx ( VariableName , VendorGuid , PtrTrack ) ;
if ( ! EFI_ERROR ( Status ) ) {
return Status ;
2011-09-02 09:49:32 +02:00
}
}
return EFI_NOT_FOUND ;
}
/**
Get index from supported language codes according to language string .
This code is used to get corresponding index in supported language codes . It can handle
RFC4646 and ISO639 language tags .
In ISO639 language tags , take 3 - characters as a delimitation to find matched string and calculate the index .
In RFC4646 language tags , take semicolon as a delimitation to find matched string and calculate the index .
For example :
SupportedLang = " engfraengfra "
Lang = " eng "
Iso639Language = TRUE
The return value is " 0 " .
Another example :
SupportedLang = " en;fr;en-US;fr-FR "
Lang = " fr-FR "
Iso639Language = FALSE
The return value is " 3 " .
@ param SupportedLang Platform supported language codes .
@ param Lang Configured language .
@ param Iso639Language A bool value to signify if the handler is operated on ISO639 or RFC4646 .
@ retval The index of language in the language codes .
* */
UINTN
GetIndexFromSupportedLangCodes (
IN CHAR8 * SupportedLang ,
IN CHAR8 * Lang ,
IN BOOLEAN Iso639Language
2011-10-28 11:55:09 +02:00
)
2011-09-02 09:49:32 +02:00
{
UINTN Index ;
UINTN CompareLength ;
UINTN LanguageLength ;
if ( Iso639Language ) {
CompareLength = ISO_639_2_ENTRY_SIZE ;
for ( Index = 0 ; Index < AsciiStrLen ( SupportedLang ) ; Index + = CompareLength ) {
if ( AsciiStrnCmp ( Lang , SupportedLang + Index , CompareLength ) = = 0 ) {
//
// Successfully find the index of Lang string in SupportedLang string.
//
Index = Index / CompareLength ;
return Index ;
}
}
ASSERT ( FALSE ) ;
return 0 ;
} else {
//
// Compare RFC4646 language code
//
Index = 0 ;
for ( LanguageLength = 0 ; Lang [ LanguageLength ] ! = ' \0 ' ; LanguageLength + + ) ;
for ( Index = 0 ; * SupportedLang ! = ' \0 ' ; Index + + , SupportedLang + = CompareLength ) {
//
// Skip ';' characters in SupportedLang
//
for ( ; * SupportedLang ! = ' \0 ' & & * SupportedLang = = ' ; ' ; SupportedLang + + ) ;
//
// Determine the length of the next language code in SupportedLang
//
for ( CompareLength = 0 ; SupportedLang [ CompareLength ] ! = ' \0 ' & & SupportedLang [ CompareLength ] ! = ' ; ' ; CompareLength + + ) ;
2011-10-28 11:55:09 +02:00
if ( ( CompareLength = = LanguageLength ) & &
2011-09-02 09:49:32 +02:00
( AsciiStrnCmp ( Lang , SupportedLang , CompareLength ) = = 0 ) ) {
//
// Successfully find the index of Lang string in SupportedLang string.
//
return Index ;
}
}
ASSERT ( FALSE ) ;
return 0 ;
}
}
/**
Get language string from supported language codes according to index .
This code is used to get corresponding language strings in supported language codes . It can handle
RFC4646 and ISO639 language tags .
In ISO639 language tags , take 3 - characters as a delimitation . Find language string according to the index .
In RFC4646 language tags , take semicolon as a delimitation . Find language string according to the index .
For example :
SupportedLang = " engfraengfra "
Index = " 1 "
Iso639Language = TRUE
The return value is " fra " .
Another example :
SupportedLang = " en;fr;en-US;fr-FR "
Index = " 1 "
Iso639Language = FALSE
The return value is " fr " .
@ param SupportedLang Platform supported language codes .
@ param Index The index in supported language codes .
@ param Iso639Language A bool value to signify if the handler is operated on ISO639 or RFC4646 .
@ retval The language string in the language codes .
* */
CHAR8 *
GetLangFromSupportedLangCodes (
IN CHAR8 * SupportedLang ,
IN UINTN Index ,
IN BOOLEAN Iso639Language
)
{
UINTN SubIndex ;
UINTN CompareLength ;
CHAR8 * Supported ;
SubIndex = 0 ;
Supported = SupportedLang ;
if ( Iso639Language ) {
//
// According to the index of Lang string in SupportedLang string to get the language.
// This code will be invoked in RUNTIME, therefore there is not a memory allocate/free operation.
// In driver entry, it pre-allocates a runtime attribute memory to accommodate this string.
//
CompareLength = ISO_639_2_ENTRY_SIZE ;
mVariableModuleGlobal - > Lang [ CompareLength ] = ' \0 ' ;
return CopyMem ( mVariableModuleGlobal - > Lang , SupportedLang + Index * CompareLength , CompareLength ) ;
2011-10-28 11:55:09 +02:00
2011-09-02 09:49:32 +02:00
} else {
while ( TRUE ) {
//
// Take semicolon as delimitation, sequentially traverse supported language codes.
//
for ( CompareLength = 0 ; * Supported ! = ' ; ' & & * Supported ! = ' \0 ' ; CompareLength + + ) {
Supported + + ;
}
if ( ( * Supported = = ' \0 ' ) & & ( SubIndex ! = Index ) ) {
//
// Have completed the traverse, but not find corrsponding string.
// This case is not allowed to happen.
//
ASSERT ( FALSE ) ;
return NULL ;
}
if ( SubIndex = = Index ) {
//
// According to the index of Lang string in SupportedLang string to get the language.
// As this code will be invoked in RUNTIME, therefore there is not memory allocate/free operation.
// In driver entry, it pre-allocates a runtime attribute memory to accommodate this string.
//
mVariableModuleGlobal - > PlatformLang [ CompareLength ] = ' \0 ' ;
return CopyMem ( mVariableModuleGlobal - > PlatformLang , Supported - CompareLength , CompareLength ) ;
}
SubIndex + + ;
//
// Skip ';' characters in Supported
//
for ( ; * Supported ! = ' \0 ' & & * Supported = = ' ; ' ; Supported + + ) ;
}
}
}
/**
2011-10-28 11:55:09 +02:00
Returns a pointer to an allocated buffer that contains the best matching language
from a set of supported languages .
This function supports both ISO 639 - 2 and RFC 4646 language codes , but language
2011-09-02 09:49:32 +02:00
code types may not be mixed in a single call to this function . This function
supports a variable argument list that allows the caller to pass in a prioritized
list of language codes to test against all the language codes in SupportedLanguages .
If SupportedLanguages is NULL , then ASSERT ( ) .
@ param [ in ] SupportedLanguages A pointer to a Null - terminated ASCII string that
2011-10-28 11:55:09 +02:00
contains a set of language codes in the format
2011-09-02 09:49:32 +02:00
specified by Iso639Language .
@ param [ in ] Iso639Language If TRUE , then all language codes are assumed to be
in ISO 639 - 2 format . If FALSE , then all language
codes are assumed to be in RFC 4646 language format
2011-10-28 11:55:09 +02:00
@ param [ in ] . . . A variable argument list that contains pointers to
2011-09-02 09:49:32 +02:00
Null - terminated ASCII strings that contain one or more
language codes in the format specified by Iso639Language .
The first language code from each of these language
code lists is used to determine if it is an exact or
2011-10-28 11:55:09 +02:00
close match to any of the language codes in
2011-09-02 09:49:32 +02:00
SupportedLanguages . Close matches only apply to RFC 4646
language codes , and the matching algorithm from RFC 4647
2011-10-28 11:55:09 +02:00
is used to determine if a close match is present . If
2011-09-02 09:49:32 +02:00
an exact or close match is found , then the matching
language code from SupportedLanguages is returned . If
no matches are found , then the next variable argument
2011-10-28 11:55:09 +02:00
parameter is evaluated . The variable argument list
2011-09-02 09:49:32 +02:00
is terminated by a NULL .
@ retval NULL The best matching language could not be found in SupportedLanguages .
2011-10-28 11:55:09 +02:00
@ retval NULL There are not enough resources available to return the best matching
2011-09-02 09:49:32 +02:00
language .
2011-10-28 11:55:09 +02:00
@ retval Other A pointer to a Null - terminated ASCII string that is the best matching
2011-09-02 09:49:32 +02:00
language in SupportedLanguages .
* */
CHAR8 *
EFIAPI
VariableGetBestLanguage (
2011-10-28 11:55:09 +02:00
IN CONST CHAR8 * SupportedLanguages ,
2011-09-02 09:49:32 +02:00
IN BOOLEAN Iso639Language ,
. . .
)
{
VA_LIST Args ;
CHAR8 * Language ;
UINTN CompareLength ;
UINTN LanguageLength ;
CONST CHAR8 * Supported ;
CHAR8 * Buffer ;
2011-09-21 07:17:50 +02:00
if ( SupportedLanguages = = NULL ) {
return NULL ;
}
2011-09-02 09:49:32 +02:00
VA_START ( Args , Iso639Language ) ;
while ( ( Language = VA_ARG ( Args , CHAR8 * ) ) ! = NULL ) {
//
// Default to ISO 639-2 mode
//
CompareLength = 3 ;
LanguageLength = MIN ( 3 , AsciiStrLen ( Language ) ) ;
//
// If in RFC 4646 mode, then determine the length of the first RFC 4646 language code in Language
//
if ( ! Iso639Language ) {
for ( LanguageLength = 0 ; Language [ LanguageLength ] ! = 0 & & Language [ LanguageLength ] ! = ' ; ' ; LanguageLength + + ) ;
}
//
// Trim back the length of Language used until it is empty
//
while ( LanguageLength > 0 ) {
//
// Loop through all language codes in SupportedLanguages
//
for ( Supported = SupportedLanguages ; * Supported ! = ' \0 ' ; Supported + = CompareLength ) {
//
// In RFC 4646 mode, then Loop through all language codes in SupportedLanguages
//
if ( ! Iso639Language ) {
//
// Skip ';' characters in Supported
//
for ( ; * Supported ! = ' \0 ' & & * Supported = = ' ; ' ; Supported + + ) ;
//
// Determine the length of the next language code in Supported
//
for ( CompareLength = 0 ; Supported [ CompareLength ] ! = 0 & & Supported [ CompareLength ] ! = ' ; ' ; CompareLength + + ) ;
//
// If Language is longer than the Supported, then skip to the next language
//
if ( LanguageLength > CompareLength ) {
continue ;
}
}
//
// See if the first LanguageLength characters in Supported match Language
//
if ( AsciiStrnCmp ( Supported , Language , LanguageLength ) = = 0 ) {
VA_END ( Args ) ;
Buffer = Iso639Language ? mVariableModuleGlobal - > Lang : mVariableModuleGlobal - > PlatformLang ;
Buffer [ CompareLength ] = ' \0 ' ;
return CopyMem ( Buffer , Supported , CompareLength ) ;
}
}
if ( Iso639Language ) {
//
// If ISO 639 mode, then each language can only be tested once
//
LanguageLength = 0 ;
} else {
//
2011-10-28 11:55:09 +02:00
// If RFC 4646 mode, then trim Language from the right to the next '-' character
2011-09-02 09:49:32 +02:00
//
for ( LanguageLength - - ; LanguageLength > 0 & & Language [ LanguageLength ] ! = ' - ' ; LanguageLength - - ) ;
}
}
}
VA_END ( Args ) ;
//
2011-10-28 11:55:09 +02:00
// No matches were found
2011-09-02 09:49:32 +02:00
//
return NULL ;
}
/**
Hook the operations in PlatformLangCodes , LangCodes , PlatformLang and Lang .
When setting Lang / LangCodes , simultaneously update PlatformLang / PlatformLangCodes .
According to UEFI spec , PlatformLangCodes / LangCodes are only set once in firmware initialization ,
and are read - only . Therefore , in variable driver , only store the original value for other use .
@ param [ in ] VariableName Name of variable .
@ param [ in ] Data Variable data .
@ param [ in ] DataSize Size of data . 0 means delete .
* */
VOID
2011-12-13 10:42:36 +01:00
AutoUpdateLangVariable (
2011-09-02 09:49:32 +02:00
IN CHAR16 * VariableName ,
IN VOID * Data ,
IN UINTN DataSize
)
{
EFI_STATUS Status ;
CHAR8 * BestPlatformLang ;
CHAR8 * BestLang ;
UINTN Index ;
UINT32 Attributes ;
VARIABLE_POINTER_TRACK Variable ;
BOOLEAN SetLanguageCodes ;
//
// Don't do updates for delete operation
//
if ( DataSize = = 0 ) {
return ;
}
SetLanguageCodes = FALSE ;
if ( StrCmp ( VariableName , L " PlatformLangCodes " ) = = 0 ) {
//
// PlatformLangCodes is a volatile variable, so it can not be updated at runtime.
//
if ( AtRuntime ( ) ) {
return ;
}
SetLanguageCodes = TRUE ;
//
// According to UEFI spec, PlatformLangCodes is only set once in firmware initialization, and is read-only
// Therefore, in variable driver, only store the original value for other use.
//
if ( mVariableModuleGlobal - > PlatformLangCodes ! = NULL ) {
FreePool ( mVariableModuleGlobal - > PlatformLangCodes ) ;
}
mVariableModuleGlobal - > PlatformLangCodes = AllocateRuntimeCopyPool ( DataSize , Data ) ;
ASSERT ( mVariableModuleGlobal - > PlatformLangCodes ! = NULL ) ;
//
2011-10-28 11:55:09 +02:00
// PlatformLang holds a single language from PlatformLangCodes,
2011-09-02 09:49:32 +02:00
// so the size of PlatformLangCodes is enough for the PlatformLang.
//
if ( mVariableModuleGlobal - > PlatformLang ! = NULL ) {
FreePool ( mVariableModuleGlobal - > PlatformLang ) ;
}
mVariableModuleGlobal - > PlatformLang = AllocateRuntimePool ( DataSize ) ;
ASSERT ( mVariableModuleGlobal - > PlatformLang ! = NULL ) ;
} else if ( StrCmp ( VariableName , L " LangCodes " ) = = 0 ) {
//
// LangCodes is a volatile variable, so it can not be updated at runtime.
//
if ( AtRuntime ( ) ) {
return ;
}
SetLanguageCodes = TRUE ;
//
// According to UEFI spec, LangCodes is only set once in firmware initialization, and is read-only
// Therefore, in variable driver, only store the original value for other use.
//
if ( mVariableModuleGlobal - > LangCodes ! = NULL ) {
FreePool ( mVariableModuleGlobal - > LangCodes ) ;
}
mVariableModuleGlobal - > LangCodes = AllocateRuntimeCopyPool ( DataSize , Data ) ;
ASSERT ( mVariableModuleGlobal - > LangCodes ! = NULL ) ;
}
2011-10-28 11:55:09 +02:00
if ( SetLanguageCodes
2011-09-02 09:49:32 +02:00
& & ( mVariableModuleGlobal - > PlatformLangCodes ! = NULL )
& & ( mVariableModuleGlobal - > LangCodes ! = NULL ) ) {
//
// Update Lang if PlatformLang is already set
// Update PlatformLang if Lang is already set
//
2011-10-19 14:40:52 +02:00
Status = FindVariable ( L " PlatformLang " , & gEfiGlobalVariableGuid , & Variable , & mVariableModuleGlobal - > VariableGlobal ) ;
2011-09-02 09:49:32 +02:00
if ( ! EFI_ERROR ( Status ) ) {
//
// Update Lang
//
VariableName = L " PlatformLang " ;
Data = GetVariableDataPtr ( Variable . CurrPtr ) ;
DataSize = Variable . CurrPtr - > DataSize ;
} else {
2011-10-19 14:40:52 +02:00
Status = FindVariable ( L " Lang " , & gEfiGlobalVariableGuid , & Variable , & mVariableModuleGlobal - > VariableGlobal ) ;
2011-09-02 09:49:32 +02:00
if ( ! EFI_ERROR ( Status ) ) {
//
// Update PlatformLang
//
VariableName = L " Lang " ;
Data = GetVariableDataPtr ( Variable . CurrPtr ) ;
DataSize = Variable . CurrPtr - > DataSize ;
} else {
//
// Neither PlatformLang nor Lang is set, directly return
//
return ;
}
}
}
2011-10-28 11:55:09 +02:00
2011-09-02 09:49:32 +02:00
//
// According to UEFI spec, "Lang" and "PlatformLang" is NV|BS|RT attributions.
//
Attributes = EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS ;
if ( StrCmp ( VariableName , L " PlatformLang " ) = = 0 ) {
//
// Update Lang when PlatformLangCodes/LangCodes were set.
//
if ( ( mVariableModuleGlobal - > PlatformLangCodes ! = NULL ) & & ( mVariableModuleGlobal - > LangCodes ! = NULL ) ) {
//
// When setting PlatformLang, firstly get most matched language string from supported language codes.
//
BestPlatformLang = VariableGetBestLanguage ( mVariableModuleGlobal - > PlatformLangCodes , FALSE , Data , NULL ) ;
if ( BestPlatformLang ! = NULL ) {
//
// Get the corresponding index in language codes.
//
Index = GetIndexFromSupportedLangCodes ( mVariableModuleGlobal - > PlatformLangCodes , BestPlatformLang , FALSE ) ;
//
// Get the corresponding ISO639 language tag according to RFC4646 language tag.
//
BestLang = GetLangFromSupportedLangCodes ( mVariableModuleGlobal - > LangCodes , Index , TRUE ) ;
//
// Successfully convert PlatformLang to Lang, and set the BestLang value into Lang variable simultaneously.
//
2011-10-19 14:40:52 +02:00
FindVariable ( L " Lang " , & gEfiGlobalVariableGuid , & Variable , & mVariableModuleGlobal - > VariableGlobal ) ;
2011-09-02 09:49:32 +02:00
Status = UpdateVariable ( L " Lang " , & gEfiGlobalVariableGuid , BestLang ,
ISO_639_2_ENTRY_SIZE + 1 , Attributes , 0 , 0 , & Variable , NULL ) ;
DEBUG ( ( EFI_D_INFO , " Variable Driver Auto Update PlatformLang, PlatformLang:%a, Lang:%a \n " , BestPlatformLang , BestLang ) ) ;
ASSERT_EFI_ERROR ( Status ) ;
}
}
} else if ( StrCmp ( VariableName , L " Lang " ) = = 0 ) {
//
// Update PlatformLang when PlatformLangCodes/LangCodes were set.
//
if ( ( mVariableModuleGlobal - > PlatformLangCodes ! = NULL ) & & ( mVariableModuleGlobal - > LangCodes ! = NULL ) ) {
//
// When setting Lang, firstly get most matched language string from supported language codes.
//
BestLang = VariableGetBestLanguage ( mVariableModuleGlobal - > LangCodes , TRUE , Data , NULL ) ;
if ( BestLang ! = NULL ) {
//
// Get the corresponding index in language codes.
//
Index = GetIndexFromSupportedLangCodes ( mVariableModuleGlobal - > LangCodes , BestLang , TRUE ) ;
//
// Get the corresponding RFC4646 language tag according to ISO639 language tag.
//
BestPlatformLang = GetLangFromSupportedLangCodes ( mVariableModuleGlobal - > PlatformLangCodes , Index , FALSE ) ;
//
// Successfully convert Lang to PlatformLang, and set the BestPlatformLang value into PlatformLang variable simultaneously.
//
2011-10-19 14:40:52 +02:00
FindVariable ( L " PlatformLang " , & gEfiGlobalVariableGuid , & Variable , & mVariableModuleGlobal - > VariableGlobal ) ;
2011-09-02 09:49:32 +02:00
2011-10-28 11:55:09 +02:00
Status = UpdateVariable ( L " PlatformLang " , & gEfiGlobalVariableGuid , BestPlatformLang ,
2011-09-02 09:49:32 +02:00
AsciiStrSize ( BestPlatformLang ) , Attributes , 0 , 0 , & Variable , NULL ) ;
DEBUG ( ( EFI_D_INFO , " Variable Driver Auto Update Lang, Lang:%a, PlatformLang:%a \n " , BestLang , BestPlatformLang ) ) ;
ASSERT_EFI_ERROR ( Status ) ;
}
}
}
}
/**
Update the variable region with Variable information . If EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS is set ,
index of associated public key is needed .
@ param [ in ] VariableName Name of variable .
@ param [ in ] VendorGuid Guid of variable .
@ param [ in ] Data Variable data .
@ param [ in ] DataSize Size of data . 0 means delete .
@ param [ in ] Attributes Attributes of the variable .
@ param [ in ] KeyIndex Index of associated public key .
@ param [ in ] MonotonicCount Value of associated monotonic count .
@ param [ in ] CacheVariable The variable information which is used to keep track of variable usage .
@ param [ in ] TimeStamp Value of associated TimeStamp .
2011-10-28 11:55:09 +02:00
2011-09-02 09:49:32 +02:00
@ retval EFI_SUCCESS The update operation is success .
@ retval EFI_OUT_OF_RESOURCES Variable region is full , can not write other data into this region .
* */
EFI_STATUS
UpdateVariable (
IN CHAR16 * VariableName ,
IN EFI_GUID * VendorGuid ,
IN VOID * Data ,
IN UINTN DataSize ,
IN UINT32 Attributes OPTIONAL ,
IN UINT32 KeyIndex OPTIONAL ,
IN UINT64 MonotonicCount OPTIONAL ,
IN VARIABLE_POINTER_TRACK * CacheVariable ,
IN EFI_TIME * TimeStamp OPTIONAL
)
{
EFI_STATUS Status ;
VARIABLE_HEADER * NextVariable ;
UINTN ScratchSize ;
UINTN ScratchDataSize ;
UINTN NonVolatileVarableStoreSize ;
UINTN VarNameOffset ;
UINTN VarDataOffset ;
UINTN VarNameSize ;
UINTN VarSize ;
BOOLEAN Volatile ;
EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL * Fvb ;
UINT8 State ;
BOOLEAN Reclaimed ;
VARIABLE_POINTER_TRACK * Variable ;
VARIABLE_POINTER_TRACK NvVariable ;
VARIABLE_STORE_HEADER * VariableStoreHeader ;
UINTN CacheOffset ;
UINTN BufSize ;
UINTN DataOffset ;
UINTN RevBufSize ;
if ( mVariableModuleGlobal - > FvbInstance = = NULL ) {
//
// The FVB protocol is not installed, so the EFI_VARIABLE_WRITE_ARCH_PROTOCOL is not installed.
//
if ( ( Attributes & EFI_VARIABLE_NON_VOLATILE ) ! = 0 ) {
//
// Trying to update NV variable prior to the installation of EFI_VARIABLE_WRITE_ARCH_PROTOCOL
//
return EFI_NOT_AVAILABLE_YET ;
} else if ( ( Attributes & EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS ) ! = 0 ) {
//
// Trying to update volatile authenticated variable prior to the installation of EFI_VARIABLE_WRITE_ARCH_PROTOCOL
// The authenticated variable perhaps is not initialized, just return here.
//
return EFI_NOT_AVAILABLE_YET ;
}
}
if ( ( CacheVariable - > CurrPtr = = NULL ) | | CacheVariable - > Volatile ) {
Variable = CacheVariable ;
} else {
//
// Update/Delete existing NV variable.
// CacheVariable points to the variable in the memory copy of Flash area
// Now let Variable points to the same variable in Flash area.
//
VariableStoreHeader = ( VARIABLE_STORE_HEADER * ) ( ( UINTN ) mVariableModuleGlobal - > VariableGlobal . NonVolatileVariableBase ) ;
2011-10-28 11:55:09 +02:00
Variable = & NvVariable ;
2011-09-02 09:49:32 +02:00
Variable - > StartPtr = GetStartPointer ( VariableStoreHeader ) ;
Variable - > EndPtr = GetEndPointer ( VariableStoreHeader ) ;
Variable - > CurrPtr = ( VARIABLE_HEADER * ) ( ( UINTN ) Variable - > StartPtr + ( ( UINTN ) CacheVariable - > CurrPtr - ( UINTN ) CacheVariable - > StartPtr ) ) ;
Variable - > Volatile = FALSE ;
2011-10-28 11:55:09 +02:00
}
2011-09-02 09:49:32 +02:00
Fvb = mVariableModuleGlobal - > FvbInstance ;
Reclaimed = FALSE ;
//
// Tricky part: Use scratch data area at the end of volatile variable store
// as a temporary storage.
//
NextVariable = GetEndPointer ( ( VARIABLE_STORE_HEADER * ) ( ( UINTN ) mVariableModuleGlobal - > VariableGlobal . VolatileVariableBase ) ) ;
ScratchSize = MAX ( PcdGet32 ( PcdMaxVariableSize ) , PcdGet32 ( PcdMaxHardwareErrorVariableSize ) ) ;
ScratchDataSize = ScratchSize - sizeof ( VARIABLE_HEADER ) - StrSize ( VariableName ) - GET_PAD_SIZE ( StrSize ( VariableName ) ) ;
if ( Variable - > CurrPtr ! = NULL ) {
//
// Update/Delete existing variable.
//
2011-10-28 11:55:09 +02:00
if ( AtRuntime ( ) ) {
2011-09-02 09:49:32 +02:00
//
2011-10-28 11:55:09 +02:00
// If AtRuntime and the variable is Volatile and Runtime Access,
// the volatile is ReadOnly, and SetVariable should be aborted and
2011-09-02 09:49:32 +02:00
// return EFI_WRITE_PROTECTED.
//
if ( Variable - > Volatile ) {
Status = EFI_WRITE_PROTECTED ;
goto Done ;
}
//
// Only variable that have NV attributes can be updated/deleted in Runtime.
//
if ( ( Variable - > CurrPtr - > Attributes & EFI_VARIABLE_NON_VOLATILE ) = = 0 ) {
Status = EFI_INVALID_PARAMETER ;
2011-10-28 11:55:09 +02:00
goto Done ;
2011-09-02 09:49:32 +02:00
}
}
//
// Setting a data variable with no access, or zero DataSize attributes
// causes it to be deleted.
2011-10-28 11:55:09 +02:00
// When the EFI_VARIABLE_APPEND_WRITE attribute is set, DataSize of zero will
// not delete the variable.
2011-09-02 09:49:32 +02:00
//
2011-10-28 11:55:09 +02:00
if ( ( ( ( Attributes & EFI_VARIABLE_APPEND_WRITE ) = = 0 ) & & ( DataSize = = 0 ) ) | | ( ( Attributes & ( EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS ) ) = = 0 ) ) {
2011-09-02 09:49:32 +02:00
State = Variable - > CurrPtr - > State ;
State & = VAR_DELETED ;
Status = UpdateVariableStore (
& mVariableModuleGlobal - > VariableGlobal ,
Variable - > Volatile ,
FALSE ,
Fvb ,
( UINTN ) & Variable - > CurrPtr - > State ,
sizeof ( UINT8 ) ,
& State
2011-10-28 11:55:09 +02:00
) ;
2011-09-02 09:49:32 +02:00
if ( ! EFI_ERROR ( Status ) ) {
UpdateVariableInfo ( VariableName , VendorGuid , Variable - > Volatile , FALSE , FALSE , TRUE , FALSE ) ;
if ( ! Variable - > Volatile ) {
CacheVariable - > CurrPtr - > State = State ;
}
}
2011-10-28 11:55:09 +02:00
goto Done ;
2011-09-02 09:49:32 +02:00
}
//
// If the variable is marked valid, and the same data has been passed in,
// then return to the caller immediately.
//
if ( DataSizeOfVariable ( Variable - > CurrPtr ) = = DataSize & &
( CompareMem ( Data , GetVariableDataPtr ( Variable - > CurrPtr ) , DataSize ) = = 0 ) & &
2011-10-28 11:55:09 +02:00
( ( Attributes & EFI_VARIABLE_APPEND_WRITE ) = = 0 ) & &
( TimeStamp = = NULL ) ) {
//
// Variable content unchanged and no need to update timestamp, just return.
//
2011-09-02 09:49:32 +02:00
UpdateVariableInfo ( VariableName , VendorGuid , Variable - > Volatile , FALSE , TRUE , FALSE , FALSE ) ;
Status = EFI_SUCCESS ;
goto Done ;
} else if ( ( Variable - > CurrPtr - > State = = VAR_ADDED ) | |
( Variable - > CurrPtr - > State = = ( VAR_ADDED & VAR_IN_DELETED_TRANSITION ) ) ) {
//
// EFI_VARIABLE_APPEND_WRITE attribute only effects for existing variable
//
if ( ( Attributes & EFI_VARIABLE_APPEND_WRITE ) ! = 0 ) {
2011-10-28 11:55:09 +02:00
//
// Cache the previous variable data into StorageArea.
//
DataOffset = sizeof ( VARIABLE_HEADER ) + Variable - > CurrPtr - > NameSize + GET_PAD_SIZE ( Variable - > CurrPtr - > NameSize ) ;
CopyMem ( mStorageArea , ( UINT8 * ) ( ( UINTN ) Variable - > CurrPtr + DataOffset ) , Variable - > CurrPtr - > DataSize ) ;
if ( CompareGuid ( VendorGuid , & gEfiImageSecurityDatabaseGuid ) | |
( CompareGuid ( VendorGuid , & gEfiGlobalVariableGuid ) & & ( StrCmp ( VariableName , EFI_KEY_EXCHANGE_KEY_NAME ) = = 0 ) ) ) {
//
// For variables with the GUID EFI_IMAGE_SECURITY_DATABASE_GUID (i.e. where the data
// buffer is formatted as EFI_SIGNATURE_LIST), the driver shall not perform an append of
// EFI_SIGNATURE_DATA values that are already part of the existing variable value.
//
BufSize = AppendSignatureList ( mStorageArea , Variable - > CurrPtr - > DataSize , Data , DataSize ) ;
if ( BufSize = = Variable - > CurrPtr - > DataSize ) {
if ( ( TimeStamp = = NULL ) | | CompareTimeStamp ( TimeStamp , & Variable - > CurrPtr - > TimeStamp ) ) {
//
// New EFI_SIGNATURE_DATA is not found and timestamp is not later
// than current timestamp, return EFI_SUCCESS directly.
//
UpdateVariableInfo ( VariableName , VendorGuid , Variable - > Volatile , FALSE , TRUE , FALSE , FALSE ) ;
Status = EFI_SUCCESS ;
goto Done ;
}
}
} else {
//
// For other Variables, append the new data to the end of previous data.
//
CopyMem ( ( UINT8 * ) ( ( UINTN ) mStorageArea + Variable - > CurrPtr - > DataSize ) , Data , DataSize ) ;
BufSize = Variable - > CurrPtr - > DataSize + DataSize ;
}
RevBufSize = MIN ( PcdGet32 ( PcdMaxVariableSize ) , ScratchDataSize ) ;
2011-09-02 09:49:32 +02:00
if ( BufSize > RevBufSize ) {
//
// If variable size (previous + current) is bigger than reserved buffer in runtime,
// return EFI_OUT_OF_RESOURCES.
//
return EFI_OUT_OF_RESOURCES ;
}
2011-10-28 11:55:09 +02:00
2011-09-02 09:49:32 +02:00
//
// Override Data and DataSize which are used for combined data area including previous and new data.
//
Data = mStorageArea ;
DataSize = BufSize ;
}
//
// Mark the old variable as in delete transition.
//
State = Variable - > CurrPtr - > State ;
State & = VAR_IN_DELETED_TRANSITION ;
Status = UpdateVariableStore (
& mVariableModuleGlobal - > VariableGlobal ,
Variable - > Volatile ,
FALSE ,
Fvb ,
( UINTN ) & Variable - > CurrPtr - > State ,
sizeof ( UINT8 ) ,
& State
2011-10-28 11:55:09 +02:00
) ;
2011-09-02 09:49:32 +02:00
if ( EFI_ERROR ( Status ) ) {
2011-10-28 11:55:09 +02:00
goto Done ;
}
2011-09-02 09:49:32 +02:00
if ( ! Variable - > Volatile ) {
CacheVariable - > CurrPtr - > State = State ;
}
2011-10-28 11:55:09 +02:00
}
2011-09-02 09:49:32 +02:00
} else {
//
// Not found existing variable. Create a new variable.
//
2011-10-28 11:55:09 +02:00
if ( ( DataSize = = 0 ) & & ( ( Attributes & EFI_VARIABLE_APPEND_WRITE ) ! = 0 ) ) {
Status = EFI_SUCCESS ;
2011-09-02 09:49:32 +02:00
goto Done ;
}
2011-10-28 11:55:09 +02:00
2011-09-02 09:49:32 +02:00
//
// Make sure we are trying to create a new variable.
2011-10-28 11:55:09 +02:00
// Setting a data variable with zero DataSize or no access attributes means to delete it.
2011-09-02 09:49:32 +02:00
//
if ( DataSize = = 0 | | ( Attributes & ( EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS ) ) = = 0 ) {
Status = EFI_NOT_FOUND ;
goto Done ;
}
2011-10-28 11:55:09 +02:00
2011-09-02 09:49:32 +02:00
//
// Only variable have NV|RT attribute can be created in Runtime.
//
if ( AtRuntime ( ) & &
( ( ( Attributes & EFI_VARIABLE_RUNTIME_ACCESS ) = = 0 ) | | ( ( Attributes & EFI_VARIABLE_NON_VOLATILE ) = = 0 ) ) ) {
Status = EFI_INVALID_PARAMETER ;
goto Done ;
2011-10-28 11:55:09 +02:00
}
2011-09-02 09:49:32 +02:00
}
//
// Function part - create a new variable and copy the data.
// Both update a variable and create a variable will come here.
SetMem ( NextVariable , ScratchSize , 0xff ) ;
NextVariable - > StartId = VARIABLE_DATA ;
//
// NextVariable->State = VAR_ADDED;
//
NextVariable - > Reserved = 0 ;
NextVariable - > PubKeyIndex = KeyIndex ;
NextVariable - > MonotonicCount = MonotonicCount ;
2011-10-28 11:55:09 +02:00
ZeroMem ( & NextVariable - > TimeStamp , sizeof ( EFI_TIME ) ) ;
2011-09-02 09:49:32 +02:00
2011-10-14 07:19:25 +02:00
if ( ( ( Attributes & EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS ) ! = 0 ) & &
2011-10-28 11:55:09 +02:00
( TimeStamp ! = NULL ) ) {
2011-10-14 07:19:25 +02:00
if ( ( Attributes & EFI_VARIABLE_APPEND_WRITE ) = = 0 ) {
CopyMem ( & NextVariable - > TimeStamp , TimeStamp , sizeof ( EFI_TIME ) ) ;
} else {
2011-09-02 09:49:32 +02:00
//
// In the case when the EFI_VARIABLE_APPEND_WRITE attribute is set, only
// when the new TimeStamp value is later than the current timestamp associated
// with the variable, we need associate the new timestamp with the updated value.
//
2011-10-28 11:55:09 +02:00
if ( Variable - > CurrPtr ! = NULL ) {
if ( CompareTimeStamp ( & Variable - > CurrPtr - > TimeStamp , TimeStamp ) ) {
CopyMem ( & NextVariable - > TimeStamp , TimeStamp , sizeof ( EFI_TIME ) ) ;
}
2011-09-02 09:49:32 +02:00
}
2011-10-14 07:19:25 +02:00
}
2011-09-02 09:49:32 +02:00
}
//
2011-10-28 11:55:09 +02:00
// The EFI_VARIABLE_APPEND_WRITE attribute will never be set in the returned
2011-09-02 09:49:32 +02:00
// Attributes bitmask parameter of a GetVariable() call.
//
NextVariable - > Attributes = Attributes & ( ~ EFI_VARIABLE_APPEND_WRITE ) ;
2011-10-28 11:55:09 +02:00
2011-09-02 09:49:32 +02:00
VarNameOffset = sizeof ( VARIABLE_HEADER ) ;
VarNameSize = StrSize ( VariableName ) ;
CopyMem (
( UINT8 * ) ( ( UINTN ) NextVariable + VarNameOffset ) ,
VariableName ,
VarNameSize
) ;
VarDataOffset = VarNameOffset + VarNameSize + GET_PAD_SIZE ( VarNameSize ) ;
CopyMem (
( UINT8 * ) ( ( UINTN ) NextVariable + VarDataOffset ) ,
Data ,
DataSize
) ;
CopyMem ( & NextVariable - > VendorGuid , VendorGuid , sizeof ( EFI_GUID ) ) ;
//
// There will be pad bytes after Data, the NextVariable->NameSize and
// NextVariable->DataSize should not include pad size so that variable
// service can get actual size in GetVariable.
//
NextVariable - > NameSize = ( UINT32 ) VarNameSize ;
NextVariable - > DataSize = ( UINT32 ) DataSize ;
//
// The actual size of the variable that stores in storage should
// include pad size.
//
VarSize = VarDataOffset + DataSize + GET_PAD_SIZE ( DataSize ) ;
if ( ( Attributes & EFI_VARIABLE_NON_VOLATILE ) ! = 0 ) {
//
// Create a nonvolatile variable.
//
Volatile = FALSE ;
NonVolatileVarableStoreSize = ( ( VARIABLE_STORE_HEADER * ) ( UINTN ) ( mVariableModuleGlobal - > VariableGlobal . NonVolatileVariableBase ) ) - > Size ;
2011-10-28 11:55:09 +02:00
if ( ( ( ( Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD ) ! = 0 )
2011-09-02 09:49:32 +02:00
& & ( ( VarSize + mVariableModuleGlobal - > HwErrVariableTotalSize ) > PcdGet32 ( PcdHwErrStorageSize ) ) )
2011-10-28 11:55:09 +02:00
| | ( ( ( Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD ) = = 0 )
2011-09-02 09:49:32 +02:00
& & ( ( VarSize + mVariableModuleGlobal - > CommonVariableTotalSize ) > NonVolatileVarableStoreSize - sizeof ( VARIABLE_STORE_HEADER ) - PcdGet32 ( PcdHwErrStorageSize ) ) ) ) {
if ( AtRuntime ( ) ) {
Status = EFI_OUT_OF_RESOURCES ;
goto Done ;
}
//
// Perform garbage collection & reclaim operation.
//
2011-10-28 11:55:09 +02:00
Status = Reclaim ( mVariableModuleGlobal - > VariableGlobal . NonVolatileVariableBase ,
2011-09-02 09:49:32 +02:00
& mVariableModuleGlobal - > NonVolatileLastVariableOffset , FALSE , Variable - > CurrPtr ) ;
if ( EFI_ERROR ( Status ) ) {
goto Done ;
}
//
// If still no enough space, return out of resources.
//
2011-10-28 11:55:09 +02:00
if ( ( ( ( Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD ) ! = 0 )
2011-09-02 09:49:32 +02:00
& & ( ( VarSize + mVariableModuleGlobal - > HwErrVariableTotalSize ) > PcdGet32 ( PcdHwErrStorageSize ) ) )
2011-10-28 11:55:09 +02:00
| | ( ( ( Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD ) = = 0 )
2011-09-02 09:49:32 +02:00
& & ( ( VarSize + mVariableModuleGlobal - > CommonVariableTotalSize ) > NonVolatileVarableStoreSize - sizeof ( VARIABLE_STORE_HEADER ) - PcdGet32 ( PcdHwErrStorageSize ) ) ) ) {
Status = EFI_OUT_OF_RESOURCES ;
goto Done ;
}
Reclaimed = TRUE ;
}
//
// Four steps
// 1. Write variable header
2011-10-28 11:55:09 +02:00
// 2. Set variable state to header valid
2011-09-02 09:49:32 +02:00
// 3. Write variable data
// 4. Set variable state to valid
//
//
// Step 1:
//
CacheOffset = mVariableModuleGlobal - > NonVolatileLastVariableOffset ;
Status = UpdateVariableStore (
& mVariableModuleGlobal - > VariableGlobal ,
FALSE ,
TRUE ,
Fvb ,
mVariableModuleGlobal - > NonVolatileLastVariableOffset ,
sizeof ( VARIABLE_HEADER ) ,
( UINT8 * ) NextVariable
) ;
if ( EFI_ERROR ( Status ) ) {
goto Done ;
}
//
// Step 2:
//
NextVariable - > State = VAR_HEADER_VALID_ONLY ;
Status = UpdateVariableStore (
& mVariableModuleGlobal - > VariableGlobal ,
FALSE ,
TRUE ,
Fvb ,
mVariableModuleGlobal - > NonVolatileLastVariableOffset + OFFSET_OF ( VARIABLE_HEADER , State ) ,
sizeof ( UINT8 ) ,
& NextVariable - > State
) ;
if ( EFI_ERROR ( Status ) ) {
goto Done ;
}
//
// Step 3:
//
Status = UpdateVariableStore (
& mVariableModuleGlobal - > VariableGlobal ,
FALSE ,
TRUE ,
Fvb ,
mVariableModuleGlobal - > NonVolatileLastVariableOffset + sizeof ( VARIABLE_HEADER ) ,
( UINT32 ) VarSize - sizeof ( VARIABLE_HEADER ) ,
( UINT8 * ) NextVariable + sizeof ( VARIABLE_HEADER )
) ;
if ( EFI_ERROR ( Status ) ) {
goto Done ;
}
//
// Step 4:
//
NextVariable - > State = VAR_ADDED ;
Status = UpdateVariableStore (
& mVariableModuleGlobal - > VariableGlobal ,
FALSE ,
TRUE ,
Fvb ,
mVariableModuleGlobal - > NonVolatileLastVariableOffset + OFFSET_OF ( VARIABLE_HEADER , State ) ,
sizeof ( UINT8 ) ,
& NextVariable - > State
) ;
if ( EFI_ERROR ( Status ) ) {
goto Done ;
}
mVariableModuleGlobal - > NonVolatileLastVariableOffset + = HEADER_ALIGN ( VarSize ) ;
if ( ( Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD ) ! = 0 ) {
mVariableModuleGlobal - > HwErrVariableTotalSize + = HEADER_ALIGN ( VarSize ) ;
} else {
mVariableModuleGlobal - > CommonVariableTotalSize + = HEADER_ALIGN ( VarSize ) ;
}
//
// update the memory copy of Flash region.
//
CopyMem ( ( UINT8 * ) mNvVariableCache + CacheOffset , ( UINT8 * ) NextVariable , VarSize ) ;
} else {
//
// Create a volatile variable.
2011-10-28 11:55:09 +02:00
//
2011-09-02 09:49:32 +02:00
Volatile = TRUE ;
if ( ( UINT32 ) ( VarSize + mVariableModuleGlobal - > VolatileLastVariableOffset ) >
( ( VARIABLE_STORE_HEADER * ) ( ( UINTN ) ( mVariableModuleGlobal - > VariableGlobal . VolatileVariableBase ) ) ) - > Size ) {
//
// Perform garbage collection & reclaim operation.
//
2011-10-28 11:55:09 +02:00
Status = Reclaim ( mVariableModuleGlobal - > VariableGlobal . VolatileVariableBase ,
2011-09-02 09:49:32 +02:00
& mVariableModuleGlobal - > VolatileLastVariableOffset , TRUE , Variable - > CurrPtr ) ;
if ( EFI_ERROR ( Status ) ) {
goto Done ;
}
//
// If still no enough space, return out of resources.
//
if ( ( UINT32 ) ( VarSize + mVariableModuleGlobal - > VolatileLastVariableOffset ) >
( ( VARIABLE_STORE_HEADER * ) ( ( UINTN ) ( mVariableModuleGlobal - > VariableGlobal . VolatileVariableBase ) ) ) - > Size
) {
Status = EFI_OUT_OF_RESOURCES ;
goto Done ;
}
Reclaimed = TRUE ;
}
NextVariable - > State = VAR_ADDED ;
Status = UpdateVariableStore (
& mVariableModuleGlobal - > VariableGlobal ,
TRUE ,
TRUE ,
Fvb ,
mVariableModuleGlobal - > VolatileLastVariableOffset ,
( UINT32 ) VarSize ,
( UINT8 * ) NextVariable
) ;
if ( EFI_ERROR ( Status ) ) {
goto Done ;
}
mVariableModuleGlobal - > VolatileLastVariableOffset + = HEADER_ALIGN ( VarSize ) ;
}
//
// Mark the old variable as deleted.
//
if ( ! Reclaimed & & ! EFI_ERROR ( Status ) & & Variable - > CurrPtr ! = NULL ) {
State = Variable - > CurrPtr - > State ;
State & = VAR_DELETED ;
Status = UpdateVariableStore (
& mVariableModuleGlobal - > VariableGlobal ,
Variable - > Volatile ,
FALSE ,
Fvb ,
( UINTN ) & Variable - > CurrPtr - > State ,
sizeof ( UINT8 ) ,
& State
) ;
2011-10-28 11:55:09 +02:00
if ( ! EFI_ERROR ( Status ) & & ! Variable - > Volatile ) {
2011-09-02 09:49:32 +02:00
CacheVariable - > CurrPtr - > State = State ;
}
}
if ( ! EFI_ERROR ( Status ) ) {
UpdateVariableInfo ( VariableName , VendorGuid , Volatile , FALSE , TRUE , FALSE , FALSE ) ;
}
Done :
return Status ;
}
/**
This code finds variable in storage blocks ( Volatile or Non - Volatile ) .
@ param VariableName Name of Variable to be found .
@ param VendorGuid Variable vendor GUID .
@ param Attributes Attribute value of the variable found .
@ param DataSize Size of Data found . If size is less than the
data , this value contains the required size .
@ param Data Data pointer .
2011-10-28 11:55:09 +02:00
2011-09-02 09:49:32 +02:00
@ return EFI_INVALID_PARAMETER Invalid parameter .
@ return EFI_SUCCESS Find the specified variable .
@ return EFI_NOT_FOUND Not found .
@ return EFI_BUFFER_TO_SMALL DataSize is too small for the result .
* */
EFI_STATUS
EFIAPI
VariableServiceGetVariable (
IN CHAR16 * VariableName ,
IN EFI_GUID * VendorGuid ,
OUT UINT32 * Attributes OPTIONAL ,
IN OUT UINTN * DataSize ,
OUT VOID * Data
)
{
EFI_STATUS Status ;
VARIABLE_POINTER_TRACK Variable ;
UINTN VarDataSize ;
if ( VariableName = = NULL | | VendorGuid = = NULL | | DataSize = = NULL ) {
return EFI_INVALID_PARAMETER ;
}
AcquireLockOnlyAtBootTime ( & mVariableModuleGlobal - > VariableGlobal . VariableServicesLock ) ;
2011-10-28 11:55:09 +02:00
2011-09-02 09:49:32 +02:00
Status = FindVariable ( VariableName , VendorGuid , & Variable , & mVariableModuleGlobal - > VariableGlobal ) ;
if ( Variable . CurrPtr = = NULL | | EFI_ERROR ( Status ) ) {
goto Done ;
}
//
// Get data size
//
VarDataSize = DataSizeOfVariable ( Variable . CurrPtr ) ;
ASSERT ( VarDataSize ! = 0 ) ;
if ( * DataSize > = VarDataSize ) {
if ( Data = = NULL ) {
Status = EFI_INVALID_PARAMETER ;
goto Done ;
}
CopyMem ( Data , GetVariableDataPtr ( Variable . CurrPtr ) , VarDataSize ) ;
if ( Attributes ! = NULL ) {
* Attributes = Variable . CurrPtr - > Attributes ;
}
* DataSize = VarDataSize ;
UpdateVariableInfo ( VariableName , VendorGuid , Variable . Volatile , TRUE , FALSE , FALSE , FALSE ) ;
2011-10-28 11:55:09 +02:00
2011-09-02 09:49:32 +02:00
Status = EFI_SUCCESS ;
goto Done ;
} else {
* DataSize = VarDataSize ;
Status = EFI_BUFFER_TOO_SMALL ;
goto Done ;
}
Done :
ReleaseLockOnlyAtBootTime ( & mVariableModuleGlobal - > VariableGlobal . VariableServicesLock ) ;
return Status ;
}
/**
This code Finds the Next available variable .
@ param VariableNameSize Size of the variable name .
@ param VariableName Pointer to variable name .
@ param VendorGuid Variable Vendor Guid .
@ return EFI_INVALID_PARAMETER Invalid parameter .
@ return EFI_SUCCESS Find the specified variable .
@ return EFI_NOT_FOUND Not found .
@ return EFI_BUFFER_TO_SMALL DataSize is too small for the result .
* */
EFI_STATUS
EFIAPI
VariableServiceGetNextVariableName (
IN OUT UINTN * VariableNameSize ,
IN OUT CHAR16 * VariableName ,
IN OUT EFI_GUID * VendorGuid
)
{
2011-10-19 14:40:52 +02:00
VARIABLE_STORE_TYPE Type ;
2011-09-02 09:49:32 +02:00
VARIABLE_POINTER_TRACK Variable ;
2011-10-19 14:40:52 +02:00
VARIABLE_POINTER_TRACK VariableInHob ;
2011-09-02 09:49:32 +02:00
UINTN VarNameSize ;
EFI_STATUS Status ;
2011-10-19 14:40:52 +02:00
VARIABLE_STORE_HEADER * VariableStoreHeader [ VariableStoreTypeMax ] ;
2011-09-02 09:49:32 +02:00
if ( VariableNameSize = = NULL | | VariableName = = NULL | | VendorGuid = = NULL ) {
return EFI_INVALID_PARAMETER ;
}
AcquireLockOnlyAtBootTime ( & mVariableModuleGlobal - > VariableGlobal . VariableServicesLock ) ;
Status = FindVariable ( VariableName , VendorGuid , & Variable , & mVariableModuleGlobal - > VariableGlobal ) ;
if ( Variable . CurrPtr = = NULL | | EFI_ERROR ( Status ) ) {
goto Done ;
}
if ( VariableName [ 0 ] ! = 0 ) {
//
// If variable name is not NULL, get next variable.
//
Variable . CurrPtr = GetNextVariablePtr ( Variable . CurrPtr ) ;
}
2011-10-19 14:40:52 +02:00
//
// 0: Volatile, 1: HOB, 2: Non-Volatile.
// The index and attributes mapping must be kept in this order as FindVariable
// makes use of this mapping to implement search algorithm.
//
VariableStoreHeader [ VariableStoreTypeVolatile ] = ( VARIABLE_STORE_HEADER * ) ( UINTN ) mVariableModuleGlobal - > VariableGlobal . VolatileVariableBase ;
VariableStoreHeader [ VariableStoreTypeHob ] = ( VARIABLE_STORE_HEADER * ) ( UINTN ) mVariableModuleGlobal - > VariableGlobal . HobVariableBase ;
VariableStoreHeader [ VariableStoreTypeNv ] = mNvVariableCache ;
2011-09-02 09:49:32 +02:00
while ( TRUE ) {
//
2011-10-19 14:40:52 +02:00
// Switch from Volatile to HOB, to Non-Volatile.
2011-09-02 09:49:32 +02:00
//
2011-10-19 14:40:52 +02:00
while ( ( Variable . CurrPtr > = Variable . EndPtr ) | |
( Variable . CurrPtr = = NULL ) | |
! IsValidVariableHeader ( Variable . CurrPtr )
) {
//
// Find current storage index
//
for ( Type = ( VARIABLE_STORE_TYPE ) 0 ; Type < VariableStoreTypeMax ; Type + + ) {
if ( ( VariableStoreHeader [ Type ] ! = NULL ) & & ( Variable . StartPtr = = GetStartPointer ( VariableStoreHeader [ Type ] ) ) ) {
break ;
}
}
ASSERT ( Type < VariableStoreTypeMax ) ;
//
// Switch to next storage
//
for ( Type + + ; Type < VariableStoreTypeMax ; Type + + ) {
if ( VariableStoreHeader [ Type ] ! = NULL ) {
break ;
}
}
//
2011-10-28 11:55:09 +02:00
// Capture the case that
2011-10-19 14:40:52 +02:00
// 1. current storage is the last one, or
// 2. no further storage
//
if ( Type = = VariableStoreTypeMax ) {
2011-09-02 09:49:32 +02:00
Status = EFI_NOT_FOUND ;
goto Done ;
}
2011-10-19 14:40:52 +02:00
Variable . StartPtr = GetStartPointer ( VariableStoreHeader [ Type ] ) ;
Variable . EndPtr = GetEndPointer ( VariableStoreHeader [ Type ] ) ;
Variable . CurrPtr = Variable . StartPtr ;
2011-09-02 09:49:32 +02:00
}
2011-10-19 14:40:52 +02:00
2011-09-02 09:49:32 +02:00
//
// Variable is found
//
2011-10-19 14:40:52 +02:00
if ( Variable . CurrPtr - > State = = VAR_ADDED ) {
2011-09-02 09:49:32 +02:00
if ( ( AtRuntime ( ) & & ( ( Variable . CurrPtr - > Attributes & EFI_VARIABLE_RUNTIME_ACCESS ) = = 0 ) ) = = 0 ) {
2011-10-19 14:40:52 +02:00
//
// Don't return NV variable when HOB overrides it
//
2011-10-28 11:55:09 +02:00
if ( ( VariableStoreHeader [ VariableStoreTypeHob ] ! = NULL ) & & ( VariableStoreHeader [ VariableStoreTypeNv ] ! = NULL ) & &
2011-10-19 14:40:52 +02:00
( Variable . StartPtr = = GetStartPointer ( VariableStoreHeader [ VariableStoreTypeNv ] ) )
) {
VariableInHob . StartPtr = GetStartPointer ( VariableStoreHeader [ VariableStoreTypeHob ] ) ;
VariableInHob . EndPtr = GetEndPointer ( VariableStoreHeader [ VariableStoreTypeHob ] ) ;
Status = FindVariableEx (
GetVariableNamePtr ( Variable . CurrPtr ) ,
& Variable . CurrPtr - > VendorGuid ,
& VariableInHob
) ;
if ( ! EFI_ERROR ( Status ) ) {
Variable . CurrPtr = GetNextVariablePtr ( Variable . CurrPtr ) ;
continue ;
}
}
2011-09-02 09:49:32 +02:00
VarNameSize = NameSizeOfVariable ( Variable . CurrPtr ) ;
ASSERT ( VarNameSize ! = 0 ) ;
if ( VarNameSize < = * VariableNameSize ) {
2011-10-19 14:40:52 +02:00
CopyMem ( VariableName , GetVariableNamePtr ( Variable . CurrPtr ) , VarNameSize ) ;
CopyMem ( VendorGuid , & Variable . CurrPtr - > VendorGuid , sizeof ( EFI_GUID ) ) ;
2011-09-02 09:49:32 +02:00
Status = EFI_SUCCESS ;
} else {
Status = EFI_BUFFER_TOO_SMALL ;
}
* VariableNameSize = VarNameSize ;
goto Done ;
}
}
Variable . CurrPtr = GetNextVariablePtr ( Variable . CurrPtr ) ;
}
Done :
ReleaseLockOnlyAtBootTime ( & mVariableModuleGlobal - > VariableGlobal . VariableServicesLock ) ;
return Status ;
}
/**
This code sets variable in storage blocks ( Volatile or Non - Volatile ) .
@ param VariableName Name of Variable to be found .
@ param VendorGuid Variable vendor GUID .
@ param Attributes Attribute value of the variable found
@ param DataSize Size of Data found . If size is less than the
data , this value contains the required size .
@ param Data Data pointer .
@ return EFI_INVALID_PARAMETER Invalid parameter .
@ return EFI_SUCCESS Set successfully .
@ return EFI_OUT_OF_RESOURCES Resource not enough to set variable .
@ return EFI_NOT_FOUND Not found .
@ return EFI_WRITE_PROTECTED Variable is read - only .
* */
EFI_STATUS
EFIAPI
VariableServiceSetVariable (
IN CHAR16 * VariableName ,
IN EFI_GUID * VendorGuid ,
IN UINT32 Attributes ,
IN UINTN DataSize ,
IN VOID * Data
)
{
VARIABLE_POINTER_TRACK Variable ;
EFI_STATUS Status ;
VARIABLE_HEADER * NextVariable ;
EFI_PHYSICAL_ADDRESS Point ;
UINTN PayloadSize ;
//
// Check input parameters.
//
if ( VariableName = = NULL | | VariableName [ 0 ] = = 0 | | VendorGuid = = NULL ) {
return EFI_INVALID_PARAMETER ;
2011-10-28 11:55:09 +02:00
}
2011-09-02 09:49:32 +02:00
if ( DataSize ! = 0 & & Data = = NULL ) {
return EFI_INVALID_PARAMETER ;
}
//
// Make sure if runtime bit is set, boot service bit is set also.
//
if ( ( Attributes & ( EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS ) ) = = EFI_VARIABLE_RUNTIME_ACCESS ) {
return EFI_INVALID_PARAMETER ;
}
//
2011-10-28 11:55:09 +02:00
// EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS and EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS attribute
2011-09-02 09:49:32 +02:00
// cannot be set both.
//
2011-10-28 11:55:09 +02:00
if ( ( ( Attributes & EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS ) = = EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS )
2011-09-02 09:49:32 +02:00
& & ( ( Attributes & EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS ) = = EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS ) ) {
return EFI_INVALID_PARAMETER ;
2011-10-28 11:55:09 +02:00
}
2011-09-02 09:49:32 +02:00
if ( ( Attributes & EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS ) = = EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS ) {
if ( DataSize < AUTHINFO_SIZE ) {
//
2011-10-28 11:55:09 +02:00
// Try to write Authenticated Variable without AuthInfo.
2011-09-02 09:49:32 +02:00
//
return EFI_SECURITY_VIOLATION ;
2011-10-28 11:55:09 +02:00
}
PayloadSize = DataSize - AUTHINFO_SIZE ;
} else if ( ( Attributes & EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS ) = = EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS ) {
//
// Sanity check for EFI_VARIABLE_AUTHENTICATION_2 descriptor.
//
if ( DataSize < OFFSET_OF_AUTHINFO2_CERT_DATA | |
DataSize < AUTHINFO2_SIZE ( Data ) | |
( ( EFI_VARIABLE_AUTHENTICATION_2 * ) Data ) - > AuthInfo . Hdr . dwLength < OFFSET_OF ( WIN_CERTIFICATE_UEFI_GUID , CertData ) ) {
return EFI_SECURITY_VIOLATION ;
}
PayloadSize = DataSize - AUTHINFO2_SIZE ( Data ) ;
2011-09-02 09:49:32 +02:00
} else {
2011-10-28 11:55:09 +02:00
PayloadSize = DataSize ;
2011-09-02 09:49:32 +02:00
}
2011-10-28 11:55:09 +02:00
2011-09-02 09:49:32 +02:00
//
// The size of the VariableName, including the Unicode Null in bytes plus
// the DataSize is limited to maximum size of PcdGet32 (PcdMaxHardwareErrorVariableSize)
// bytes for HwErrRec, and PcdGet32 (PcdMaxVariableSize) bytes for the others.
//
if ( ( Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD ) = = EFI_VARIABLE_HARDWARE_ERROR_RECORD ) {
if ( ( PayloadSize > PcdGet32 ( PcdMaxHardwareErrorVariableSize ) ) | |
( sizeof ( VARIABLE_HEADER ) + StrSize ( VariableName ) + PayloadSize > PcdGet32 ( PcdMaxHardwareErrorVariableSize ) ) ) {
return EFI_INVALID_PARAMETER ;
}
//
// According to UEFI spec, HARDWARE_ERROR_RECORD variable name convention should be L"HwErrRecXXXX".
//
if ( StrnCmp ( VariableName , L " HwErrRec " , StrLen ( L " HwErrRec " ) ) ! = 0 ) {
return EFI_INVALID_PARAMETER ;
}
} else {
//
// The size of the VariableName, including the Unicode Null in bytes plus
// the DataSize is limited to maximum size of PcdGet32 (PcdMaxVariableSize) bytes.
//
if ( ( PayloadSize > PcdGet32 ( PcdMaxVariableSize ) ) | |
( sizeof ( VARIABLE_HEADER ) + StrSize ( VariableName ) + PayloadSize > PcdGet32 ( PcdMaxVariableSize ) ) ) {
return EFI_INVALID_PARAMETER ;
2011-10-28 11:55:09 +02:00
}
}
2011-09-02 09:49:32 +02:00
AcquireLockOnlyAtBootTime ( & mVariableModuleGlobal - > VariableGlobal . VariableServicesLock ) ;
//
// Consider reentrant in MCA/INIT/NMI. It needs be reupdated.
//
if ( 1 < InterlockedIncrement ( & mVariableModuleGlobal - > VariableGlobal . ReentrantState ) ) {
Point = mVariableModuleGlobal - > VariableGlobal . NonVolatileVariableBase ;
//
// Parse non-volatile variable data and get last variable offset.
//
NextVariable = GetStartPointer ( ( VARIABLE_STORE_HEADER * ) ( UINTN ) Point ) ;
2011-10-28 11:55:09 +02:00
while ( ( NextVariable < GetEndPointer ( ( VARIABLE_STORE_HEADER * ) ( UINTN ) Point ) )
2011-09-02 09:49:32 +02:00
& & IsValidVariableHeader ( NextVariable ) ) {
NextVariable = GetNextVariablePtr ( NextVariable ) ;
}
mVariableModuleGlobal - > NonVolatileLastVariableOffset = ( UINTN ) NextVariable - ( UINTN ) Point ;
}
//
// Check whether the input variable is already existed.
//
FindVariable ( VariableName , VendorGuid , & Variable , & mVariableModuleGlobal - > VariableGlobal ) ;
//
// Hook the operation of setting PlatformLangCodes/PlatformLang and LangCodes/Lang.
//
AutoUpdateLangVariable ( VariableName , Data , DataSize ) ;
//
// Process PK, KEK, Sigdb seperately.
//
if ( CompareGuid ( VendorGuid , & gEfiGlobalVariableGuid ) & & ( StrCmp ( VariableName , EFI_PLATFORM_KEY_NAME ) = = 0 ) ) {
Status = ProcessVarWithPk ( VariableName , VendorGuid , Data , DataSize , & Variable , Attributes , TRUE ) ;
} else if ( CompareGuid ( VendorGuid , & gEfiGlobalVariableGuid ) & & ( StrCmp ( VariableName , EFI_KEY_EXCHANGE_KEY_NAME ) = = 0 ) ) {
Status = ProcessVarWithPk ( VariableName , VendorGuid , Data , DataSize , & Variable , Attributes , FALSE ) ;
} else if ( CompareGuid ( VendorGuid , & gEfiImageSecurityDatabaseGuid ) & & ( ( Attributes & EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS ) = = 0 ) ) {
Status = ProcessVarWithKek ( VariableName , VendorGuid , Data , DataSize , & Variable , Attributes ) ;
} else {
Status = ProcessVariable ( VariableName , VendorGuid , Data , DataSize , & Variable , Attributes ) ;
}
InterlockedDecrement ( & mVariableModuleGlobal - > VariableGlobal . ReentrantState ) ;
ReleaseLockOnlyAtBootTime ( & mVariableModuleGlobal - > VariableGlobal . VariableServicesLock ) ;
return Status ;
}
/**
This code returns information about the EFI variables .
@ param Attributes Attributes bitmask to specify the type of variables
on which to return information .
@ param MaximumVariableStorageSize Pointer to the maximum size of the storage space available
for the EFI variables associated with the attributes specified .
@ param RemainingVariableStorageSize Pointer to the remaining size of the storage space available
for EFI variables associated with the attributes specified .
@ param MaximumVariableSize Pointer to the maximum size of an individual EFI variables
associated with the attributes specified .
@ return EFI_INVALID_PARAMETER An invalid combination of attribute bits was supplied .
@ return EFI_SUCCESS Query successfully .
@ return EFI_UNSUPPORTED The attribute is not supported on this platform .
* */
EFI_STATUS
EFIAPI
VariableServiceQueryVariableInfo (
IN UINT32 Attributes ,
OUT UINT64 * MaximumVariableStorageSize ,
OUT UINT64 * RemainingVariableStorageSize ,
OUT UINT64 * MaximumVariableSize
)
{
VARIABLE_HEADER * Variable ;
VARIABLE_HEADER * NextVariable ;
UINT64 VariableSize ;
VARIABLE_STORE_HEADER * VariableStoreHeader ;
UINT64 CommonVariableTotalSize ;
UINT64 HwErrVariableTotalSize ;
CommonVariableTotalSize = 0 ;
HwErrVariableTotalSize = 0 ;
if ( MaximumVariableStorageSize = = NULL | | RemainingVariableStorageSize = = NULL | | MaximumVariableSize = = NULL | | Attributes = = 0 ) {
return EFI_INVALID_PARAMETER ;
}
if ( ( Attributes & ( EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_HARDWARE_ERROR_RECORD ) ) = = 0 ) {
//
// Make sure the Attributes combination is supported by the platform.
//
2011-10-28 11:55:09 +02:00
return EFI_UNSUPPORTED ;
2011-09-02 09:49:32 +02:00
} else if ( ( Attributes & ( EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS ) ) = = EFI_VARIABLE_RUNTIME_ACCESS ) {
//
// Make sure if runtime bit is set, boot service bit is set also.
//
return EFI_INVALID_PARAMETER ;
} else if ( AtRuntime ( ) & & ( ( Attributes & EFI_VARIABLE_RUNTIME_ACCESS ) = = 0 ) ) {
//
// Make sure RT Attribute is set if we are in Runtime phase.
//
return EFI_INVALID_PARAMETER ;
} else if ( ( Attributes & ( EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_HARDWARE_ERROR_RECORD ) ) = = EFI_VARIABLE_HARDWARE_ERROR_RECORD ) {
//
// Make sure Hw Attribute is set with NV.
//
return EFI_INVALID_PARAMETER ;
}
AcquireLockOnlyAtBootTime ( & mVariableModuleGlobal - > VariableGlobal . VariableServicesLock ) ;
if ( ( Attributes & EFI_VARIABLE_NON_VOLATILE ) = = 0 ) {
//
// Query is Volatile related.
//
VariableStoreHeader = ( VARIABLE_STORE_HEADER * ) ( ( UINTN ) mVariableModuleGlobal - > VariableGlobal . VolatileVariableBase ) ;
} else {
//
// Query is Non-Volatile related.
//
VariableStoreHeader = mNvVariableCache ;
}
//
// Now let's fill *MaximumVariableStorageSize *RemainingVariableStorageSize
// with the storage size (excluding the storage header size).
//
* MaximumVariableStorageSize = VariableStoreHeader - > Size - sizeof ( VARIABLE_STORE_HEADER ) ;
//
// Harware error record variable needs larger size.
//
if ( ( Attributes & ( EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_HARDWARE_ERROR_RECORD ) ) = = ( EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_HARDWARE_ERROR_RECORD ) ) {
* MaximumVariableStorageSize = PcdGet32 ( PcdHwErrStorageSize ) ;
* MaximumVariableSize = PcdGet32 ( PcdMaxHardwareErrorVariableSize ) - sizeof ( VARIABLE_HEADER ) ;
} else {
if ( ( Attributes & EFI_VARIABLE_NON_VOLATILE ) ! = 0 ) {
ASSERT ( PcdGet32 ( PcdHwErrStorageSize ) < VariableStoreHeader - > Size ) ;
* MaximumVariableStorageSize = VariableStoreHeader - > Size - sizeof ( VARIABLE_STORE_HEADER ) - PcdGet32 ( PcdHwErrStorageSize ) ;
}
//
// Let *MaximumVariableSize be PcdGet32 (PcdMaxVariableSize) with the exception of the variable header size.
//
* MaximumVariableSize = PcdGet32 ( PcdMaxVariableSize ) - sizeof ( VARIABLE_HEADER ) ;
}
//
// Point to the starting address of the variables.
//
Variable = GetStartPointer ( VariableStoreHeader ) ;
//
// Now walk through the related variable store.
//
while ( ( Variable < GetEndPointer ( VariableStoreHeader ) ) & & IsValidVariableHeader ( Variable ) ) {
NextVariable = GetNextVariablePtr ( Variable ) ;
VariableSize = ( UINT64 ) ( UINTN ) NextVariable - ( UINT64 ) ( UINTN ) Variable ;
if ( AtRuntime ( ) ) {
//
// We don't take the state of the variables in mind
// when calculating RemainingVariableStorageSize,
// since the space occupied by variables not marked with
// VAR_ADDED is not allowed to be reclaimed in Runtime.
//
if ( ( Variable - > Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD ) = = EFI_VARIABLE_HARDWARE_ERROR_RECORD ) {
HwErrVariableTotalSize + = VariableSize ;
} else {
CommonVariableTotalSize + = VariableSize ;
}
} else {
//
// Only care about Variables with State VAR_ADDED, because
// the space not marked as VAR_ADDED is reclaimable now.
//
if ( Variable - > State = = VAR_ADDED ) {
if ( ( Variable - > Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD ) = = EFI_VARIABLE_HARDWARE_ERROR_RECORD ) {
HwErrVariableTotalSize + = VariableSize ;
} else {
CommonVariableTotalSize + = VariableSize ;
}
}
}
//
// Go to the next one.
//
Variable = NextVariable ;
}
if ( ( Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD ) = = EFI_VARIABLE_HARDWARE_ERROR_RECORD ) {
* RemainingVariableStorageSize = * MaximumVariableStorageSize - HwErrVariableTotalSize ;
} else {
* RemainingVariableStorageSize = * MaximumVariableStorageSize - CommonVariableTotalSize ;
}
if ( * RemainingVariableStorageSize < sizeof ( VARIABLE_HEADER ) ) {
* MaximumVariableSize = 0 ;
} else if ( ( * RemainingVariableStorageSize - sizeof ( VARIABLE_HEADER ) ) < * MaximumVariableSize ) {
* MaximumVariableSize = * RemainingVariableStorageSize - sizeof ( VARIABLE_HEADER ) ;
}
ReleaseLockOnlyAtBootTime ( & mVariableModuleGlobal - > VariableGlobal . VariableServicesLock ) ;
return EFI_SUCCESS ;
}
/**
This function reclaims variable storage if free size is below the threshold .
2011-10-28 11:55:09 +02:00
2011-09-02 09:49:32 +02:00
* */
VOID
ReclaimForOS (
VOID
)
{
EFI_STATUS Status ;
UINTN CommonVariableSpace ;
UINTN RemainingCommonVariableSpace ;
UINTN RemainingHwErrVariableSpace ;
2011-10-28 11:55:09 +02:00
Status = EFI_SUCCESS ;
2011-09-02 09:49:32 +02:00
CommonVariableSpace = ( ( VARIABLE_STORE_HEADER * ) ( ( UINTN ) ( mVariableModuleGlobal - > VariableGlobal . NonVolatileVariableBase ) ) ) - > Size - sizeof ( VARIABLE_STORE_HEADER ) - PcdGet32 ( PcdHwErrStorageSize ) ; //Allowable max size of common variable storage space
RemainingCommonVariableSpace = CommonVariableSpace - mVariableModuleGlobal - > CommonVariableTotalSize ;
RemainingHwErrVariableSpace = PcdGet32 ( PcdHwErrStorageSize ) - mVariableModuleGlobal - > HwErrVariableTotalSize ;
//
// Check if the free area is blow a threshold.
//
if ( ( RemainingCommonVariableSpace < PcdGet32 ( PcdMaxVariableSize ) )
2011-10-28 11:55:09 +02:00
| | ( ( PcdGet32 ( PcdHwErrStorageSize ) ! = 0 ) & &
2011-09-02 09:49:32 +02:00
( RemainingHwErrVariableSpace < PcdGet32 ( PcdMaxHardwareErrorVariableSize ) ) ) ) {
Status = Reclaim (
mVariableModuleGlobal - > VariableGlobal . NonVolatileVariableBase ,
& mVariableModuleGlobal - > NonVolatileLastVariableOffset ,
FALSE ,
NULL
) ;
ASSERT_EFI_ERROR ( Status ) ;
}
}
/**
Initializes variable write service after FVB was ready .
@ retval EFI_SUCCESS Function successfully executed .
@ retval Others Fail to initialize the variable service .
* */
EFI_STATUS
VariableWriteServiceInitialize (
VOID
)
{
EFI_STATUS Status ;
VARIABLE_STORE_HEADER * VariableStoreHeader ;
UINTN Index ;
UINT8 Data ;
EFI_PHYSICAL_ADDRESS VariableStoreBase ;
2011-10-19 14:40:52 +02:00
VARIABLE_HEADER * Variable ;
VOID * VariableData ;
2011-09-02 09:49:32 +02:00
VariableStoreBase = mVariableModuleGlobal - > VariableGlobal . NonVolatileVariableBase ;
VariableStoreHeader = ( VARIABLE_STORE_HEADER * ) ( UINTN ) VariableStoreBase ;
2011-10-28 11:55:09 +02:00
2011-09-02 09:49:32 +02:00
//
// Check if the free area is really free.
//
2011-10-19 14:40:52 +02:00
for ( Index = mVariableModuleGlobal - > NonVolatileLastVariableOffset ; Index < VariableStoreHeader - > Size ; Index + + ) {
2011-09-02 09:49:32 +02:00
Data = ( ( UINT8 * ) mNvVariableCache ) [ Index ] ;
if ( Data ! = 0xff ) {
//
// There must be something wrong in variable store, do reclaim operation.
//
Status = Reclaim (
mVariableModuleGlobal - > VariableGlobal . NonVolatileVariableBase ,
& mVariableModuleGlobal - > NonVolatileLastVariableOffset ,
FALSE ,
NULL
) ;
if ( EFI_ERROR ( Status ) ) {
return Status ;
}
break ;
}
}
2011-10-28 11:55:09 +02:00
2011-10-19 14:40:52 +02:00
//
// Flush the HOB variable to flash and invalidate HOB variable.
//
if ( mVariableModuleGlobal - > VariableGlobal . HobVariableBase ! = 0 ) {
//
// Clear the HobVariableBase to avoid SetVariable() updating the variable in HOB
//
VariableStoreHeader = ( VARIABLE_STORE_HEADER * ) ( UINTN ) mVariableModuleGlobal - > VariableGlobal . HobVariableBase ;
mVariableModuleGlobal - > VariableGlobal . HobVariableBase = 0 ;
for ( Variable = GetStartPointer ( VariableStoreHeader )
; ( Variable < GetEndPointer ( VariableStoreHeader ) & & IsValidVariableHeader ( Variable ) )
; Variable = GetNextVariablePtr ( Variable )
) {
ASSERT ( Variable - > State = = VAR_ADDED ) ;
ASSERT ( ( Variable - > Attributes & EFI_VARIABLE_NON_VOLATILE ) ! = 0 ) ;
VariableData = GetVariableDataPtr ( Variable ) ;
Status = VariableServiceSetVariable (
GetVariableNamePtr ( Variable ) ,
& Variable - > VendorGuid ,
Variable - > Attributes ,
Variable - > DataSize ,
VariableData
) ;
ASSERT_EFI_ERROR ( Status ) ;
}
}
2011-09-02 09:49:32 +02:00
//
// Authenticated variable initialize.
//
Status = AutenticatedVariableServiceInitialize ( ) ;
return Status ;
}
/**
Initializes variable store area for non - volatile and volatile variable .
@ retval EFI_SUCCESS Function successfully executed .
@ retval EFI_OUT_OF_RESOURCES Fail to allocate enough memory resource .
* */
EFI_STATUS
VariableCommonInitialize (
VOID
)
{
EFI_STATUS Status ;
VARIABLE_STORE_HEADER * VolatileVariableStore ;
VARIABLE_STORE_HEADER * VariableStoreHeader ;
VARIABLE_HEADER * NextVariable ;
EFI_PHYSICAL_ADDRESS TempVariableStoreHeader ;
EFI_PHYSICAL_ADDRESS VariableStoreBase ;
UINT64 VariableStoreLength ;
UINTN ScratchSize ;
UINTN VariableSize ;
2011-10-19 14:40:52 +02:00
EFI_HOB_GUID_TYPE * GuidHob ;
2011-09-02 09:49:32 +02:00
//
// Allocate runtime memory for variable driver global structure.
//
mVariableModuleGlobal = AllocateRuntimeZeroPool ( sizeof ( VARIABLE_MODULE_GLOBAL ) ) ;
if ( mVariableModuleGlobal = = NULL ) {
return EFI_OUT_OF_RESOURCES ;
}
InitializeLock ( & mVariableModuleGlobal - > VariableGlobal . VariableServicesLock , TPL_NOTIFY ) ;
//
// 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
2011-10-28 11:55:09 +02:00
// ensure that the value of PcdHwErrStorageSize is less than or equal to the value of
2011-09-02 09:49:32 +02:00
// PcdFlashNvStorageVariableSize.
//
ASSERT ( PcdGet32 ( PcdHwErrStorageSize ) < = PcdGet32 ( PcdFlashNvStorageVariableSize ) ) ;
2011-10-19 14:40:52 +02:00
//
// Get HOB variable store.
//
GuidHob = GetFirstGuidHob ( & gEfiAuthenticatedVariableGuid ) ;
if ( GuidHob ! = NULL ) {
VariableStoreHeader = GET_GUID_HOB_DATA ( GuidHob ) ;
if ( GetVariableStoreStatus ( VariableStoreHeader ) = = EfiValid ) {
mVariableModuleGlobal - > VariableGlobal . HobVariableBase = ( EFI_PHYSICAL_ADDRESS ) ( UINTN ) VariableStoreHeader ;
} else {
DEBUG ( ( EFI_D_ERROR , " HOB Variable Store header is corrupted! \n " ) ) ;
}
}
2011-09-02 09:49:32 +02:00
//
// Allocate memory for volatile variable store, note that there is a scratch space to store scratch data.
//
ScratchSize = MAX ( PcdGet32 ( PcdMaxVariableSize ) , PcdGet32 ( PcdMaxHardwareErrorVariableSize ) ) ;
VolatileVariableStore = AllocateRuntimePool ( PcdGet32 ( PcdVariableStoreSize ) + ScratchSize ) ;
if ( VolatileVariableStore = = NULL ) {
FreePool ( mVariableModuleGlobal ) ;
return EFI_OUT_OF_RESOURCES ;
}
SetMem ( VolatileVariableStore , PcdGet32 ( PcdVariableStoreSize ) + ScratchSize , 0xff ) ;
//
// Initialize Variable Specific Data.
//
mVariableModuleGlobal - > VariableGlobal . VolatileVariableBase = ( EFI_PHYSICAL_ADDRESS ) ( UINTN ) VolatileVariableStore ;
mVariableModuleGlobal - > VolatileLastVariableOffset = ( UINTN ) GetStartPointer ( VolatileVariableStore ) - ( UINTN ) VolatileVariableStore ;
mVariableModuleGlobal - > FvbInstance = NULL ;
CopyGuid ( & VolatileVariableStore - > Signature , & gEfiAuthenticatedVariableGuid ) ;
VolatileVariableStore - > Size = PcdGet32 ( PcdVariableStoreSize ) ;
VolatileVariableStore - > Format = VARIABLE_STORE_FORMATTED ;
VolatileVariableStore - > State = VARIABLE_STORE_HEALTHY ;
VolatileVariableStore - > Reserved = 0 ;
VolatileVariableStore - > Reserved1 = 0 ;
//
2011-10-19 14:40:52 +02:00
// Get non-volatile variable store.
2011-09-02 09:49:32 +02:00
//
TempVariableStoreHeader = ( EFI_PHYSICAL_ADDRESS ) PcdGet64 ( PcdFlashNvStorageVariableBase64 ) ;
if ( TempVariableStoreHeader = = 0 ) {
TempVariableStoreHeader = ( EFI_PHYSICAL_ADDRESS ) PcdGet32 ( PcdFlashNvStorageVariableBase ) ;
}
2011-12-13 10:42:36 +01:00
//
// Check if the Firmware Volume is not corrupted
//
if ( ( ( ( EFI_FIRMWARE_VOLUME_HEADER * ) ( UINTN ) ( TempVariableStoreHeader ) ) - > Signature ! = EFI_FVH_SIGNATURE ) | |
( ! CompareGuid ( & gEfiSystemNvDataFvGuid , & ( ( EFI_FIRMWARE_VOLUME_HEADER * ) ( UINTN ) ( TempVariableStoreHeader ) ) - > FileSystemGuid ) ) ) {
Status = EFI_VOLUME_CORRUPTED ;
DEBUG ( ( EFI_D_ERROR , " Firmware Volume for Variable Store is corrupted \n " ) ) ;
goto Done ;
}
2011-09-02 09:49:32 +02:00
VariableStoreBase = TempVariableStoreHeader + \
( ( ( EFI_FIRMWARE_VOLUME_HEADER * ) ( UINTN ) ( TempVariableStoreHeader ) ) - > HeaderLength ) ;
VariableStoreLength = ( UINT64 ) PcdGet32 ( PcdFlashNvStorageVariableSize ) - \
( ( ( EFI_FIRMWARE_VOLUME_HEADER * ) ( UINTN ) ( TempVariableStoreHeader ) ) - > HeaderLength ) ;
mVariableModuleGlobal - > VariableGlobal . NonVolatileVariableBase = VariableStoreBase ;
VariableStoreHeader = ( VARIABLE_STORE_HEADER * ) ( UINTN ) VariableStoreBase ;
if ( GetVariableStoreStatus ( VariableStoreHeader ) ! = EfiValid ) {
Status = EFI_VOLUME_CORRUPTED ;
DEBUG ( ( EFI_D_INFO , " Variable Store header is corrupted \n " ) ) ;
goto Done ;
2011-10-28 11:55:09 +02:00
}
2011-09-02 09:49:32 +02:00
ASSERT ( VariableStoreHeader - > Size = = VariableStoreLength ) ;
2011-10-28 11:55:09 +02:00
2011-09-02 09:49:32 +02:00
//
// Parse non-volatile variable data and get last variable offset.
//
NextVariable = GetStartPointer ( ( VARIABLE_STORE_HEADER * ) ( UINTN ) VariableStoreBase ) ;
while ( IsValidVariableHeader ( NextVariable ) ) {
VariableSize = NextVariable - > NameSize + NextVariable - > DataSize + sizeof ( VARIABLE_HEADER ) ;
if ( ( NextVariable - > Attributes & ( EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_HARDWARE_ERROR_RECORD ) ) = = ( EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_HARDWARE_ERROR_RECORD ) ) {
mVariableModuleGlobal - > HwErrVariableTotalSize + = HEADER_ALIGN ( VariableSize ) ;
} else {
mVariableModuleGlobal - > CommonVariableTotalSize + = HEADER_ALIGN ( VariableSize ) ;
}
NextVariable = GetNextVariablePtr ( NextVariable ) ;
}
mVariableModuleGlobal - > NonVolatileLastVariableOffset = ( UINTN ) NextVariable - ( UINTN ) VariableStoreBase ;
2011-10-28 11:55:09 +02:00
2011-09-02 09:49:32 +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
//
mNvVariableCache = AllocateRuntimeZeroPool ( ( UINTN ) VariableStoreLength ) ;
if ( mNvVariableCache = = NULL ) {
Status = EFI_OUT_OF_RESOURCES ;
goto Done ;
}
CopyMem ( mNvVariableCache , ( CHAR8 * ) ( UINTN ) VariableStoreBase , ( UINTN ) VariableStoreLength ) ;
Status = EFI_SUCCESS ;
Done :
if ( EFI_ERROR ( Status ) ) {
FreePool ( mVariableModuleGlobal ) ;
FreePool ( VolatileVariableStore ) ;
}
return Status ;
}
/**
Get the proper fvb handle and / or fvb protocol by the given Flash address .
@ param [ in ] Address The Flash address .
@ param [ out ] FvbHandle In output , if it is not NULL , it points to the proper FVB handle .
@ param [ out ] FvbProtocol In output , if it is not NULL , it points to the proper FVB protocol .
* */
EFI_STATUS
GetFvbInfoByAddress (
IN EFI_PHYSICAL_ADDRESS Address ,
OUT EFI_HANDLE * FvbHandle OPTIONAL ,
OUT EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL * * FvbProtocol OPTIONAL
)
{
EFI_STATUS Status ;
EFI_HANDLE * HandleBuffer ;
UINTN HandleCount ;
UINTN Index ;
EFI_PHYSICAL_ADDRESS FvbBaseAddress ;
EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL * Fvb ;
EFI_FIRMWARE_VOLUME_HEADER * FwVolHeader ;
EFI_FVB_ATTRIBUTES_2 Attributes ;
2011-10-28 11:55:09 +02:00
2011-09-02 09:49:32 +02:00
//
// Get all FVB handles.
//
Status = GetFvbCountAndBuffer ( & HandleCount , & HandleBuffer ) ;
if ( EFI_ERROR ( Status ) ) {
return EFI_NOT_FOUND ;
}
//
// Get the FVB to access variable store.
//
Fvb = NULL ;
for ( Index = 0 ; Index < HandleCount ; Index + = 1 , Status = EFI_NOT_FOUND , Fvb = NULL ) {
Status = GetFvbByHandle ( HandleBuffer [ Index ] , & Fvb ) ;
if ( EFI_ERROR ( Status ) ) {
Status = EFI_NOT_FOUND ;
break ;
}
//
// Ensure this FVB protocol supported Write operation.
//
Status = Fvb - > GetAttributes ( Fvb , & Attributes ) ;
if ( EFI_ERROR ( Status ) | | ( ( Attributes & EFI_FVB2_WRITE_STATUS ) = = 0 ) ) {
2011-10-28 11:55:09 +02:00
continue ;
2011-09-02 09:49:32 +02:00
}
2011-10-28 11:55:09 +02:00
2011-09-02 09:49:32 +02:00
//
// Compare the address and select the right one.
//
Status = Fvb - > GetPhysicalAddress ( Fvb , & FvbBaseAddress ) ;
if ( EFI_ERROR ( Status ) ) {
continue ;
}
FwVolHeader = ( EFI_FIRMWARE_VOLUME_HEADER * ) ( ( UINTN ) FvbBaseAddress ) ;
if ( ( Address > = FvbBaseAddress ) & & ( Address < ( FvbBaseAddress + FwVolHeader - > FvLength ) ) ) {
if ( FvbHandle ! = NULL ) {
* FvbHandle = HandleBuffer [ Index ] ;
}
if ( FvbProtocol ! = NULL ) {
* FvbProtocol = Fvb ;
}
Status = EFI_SUCCESS ;
break ;
}
}
FreePool ( HandleBuffer ) ;
if ( Fvb = = NULL ) {
Status = EFI_NOT_FOUND ;
}
2011-10-28 11:55:09 +02:00
return Status ;
2011-09-02 09:49:32 +02:00
}