2 The common variable operation routines shared by DXE_RUNTIME variable
3 module and DXE_SMM variable module.
5 Caution: This module requires additional review when modified.
6 This driver will have external input - variable data. They may be input in SMM mode.
7 This external input must be validated carefully to avoid security issue like
8 buffer overflow, integer overflow.
10 VariableServiceGetNextVariableName () and VariableServiceQueryVariableInfo() are external API.
11 They need check input parameter.
13 VariableServiceGetVariable() and VariableServiceSetVariable() are external API
14 to receive datasize and data buffer. The size should be checked carefully.
16 VariableServiceSetVariable() should also check authenticate data to avoid buffer overflow,
17 integer overflow. It should also check attribute to avoid authentication bypass.
19 Copyright (c) 2006 - 2017, Intel Corporation. All rights reserved.<BR>
20 (C) Copyright 2015 Hewlett Packard Enterprise Development LP<BR>
21 This program and the accompanying materials
22 are licensed and made available under the terms and conditions of the BSD License
23 which accompanies this distribution. The full text of the license may be found at
24 http://opensource.org/licenses/bsd-license.php
26 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
27 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
33 VARIABLE_MODULE_GLOBAL
*mVariableModuleGlobal
;
36 /// Define a memory cache that improves the search performance for a variable.
38 VARIABLE_STORE_HEADER
*mNvVariableCache
= NULL
;
41 /// Memory cache of Fv Header.
43 EFI_FIRMWARE_VOLUME_HEADER
*mNvFvHeaderCache
= NULL
;
46 /// The memory entry used for variable statistics data.
48 VARIABLE_INFO_ENTRY
*gVariableInfo
= NULL
;
51 /// The flag to indicate whether the platform has left the DXE phase of execution.
53 BOOLEAN mEndOfDxe
= FALSE
;
56 /// It indicates the var check request source.
57 /// In the implementation, DXE is regarded as untrusted, and SMM is trusted.
59 VAR_CHECK_REQUEST_SOURCE mRequestSource
= VarCheckFromUntrusted
;
62 // It will record the current boot error flag before EndOfDxe.
64 VAR_ERROR_FLAG mCurrentBootVarErrFlag
= VAR_ERROR_FLAG_NO_ERROR
;
66 VARIABLE_ENTRY_PROPERTY mVariableEntryProperty
[] = {
68 &gEdkiiVarErrorFlagGuid
,
71 VAR_CHECK_VARIABLE_PROPERTY_REVISION
,
72 VAR_CHECK_VARIABLE_PROPERTY_READ_ONLY
,
73 VARIABLE_ATTRIBUTE_NV_BS_RT
,
74 sizeof (VAR_ERROR_FLAG
),
75 sizeof (VAR_ERROR_FLAG
)
80 AUTH_VAR_LIB_CONTEXT_IN mAuthContextIn
= {
81 AUTH_VAR_LIB_CONTEXT_IN_STRUCT_VERSION
,
83 // StructSize, TO BE FILLED
87 // MaxAuthVariableSize, TO BE FILLED
90 VariableExLibFindVariable
,
91 VariableExLibFindNextVariable
,
92 VariableExLibUpdateVariable
,
93 VariableExLibGetScratchBuffer
,
94 VariableExLibCheckRemainingSpaceForConsistency
,
95 VariableExLibAtRuntime
,
98 AUTH_VAR_LIB_CONTEXT_OUT mAuthContextOut
;
101 Initialization for MOR Lock Control.
103 @retval EFI_SUCEESS MorLock initialization success.
104 @return Others Some error occurs.
112 This service is an MOR/MorLock checker handler for the SetVariable().
114 @param VariableName the name of the vendor's variable, as a
115 Null-Terminated Unicode String
116 @param VendorGuid Unify identifier for vendor.
117 @param Attributes Point to memory location to return the attributes of variable. If the point
118 is NULL, the parameter would be ignored.
119 @param DataSize The size in bytes of Data-Buffer.
120 @param Data Point to the content of the variable.
122 @retval EFI_SUCCESS The MOR/MorLock check pass, and Variable driver can store the variable data.
123 @retval EFI_INVALID_PARAMETER The MOR/MorLock data or data size or attributes is not allowed for MOR variable.
124 @retval EFI_ACCESS_DENIED The MOR/MorLock is locked.
125 @retval EFI_ALREADY_STARTED The MorLock variable is handled inside this function.
126 Variable driver can just return EFI_SUCCESS.
129 SetVariableCheckHandlerMor (
130 IN CHAR16
*VariableName
,
131 IN EFI_GUID
*VendorGuid
,
132 IN UINT32 Attributes
,
138 Routine used to track statistical information about variable usage.
139 The data is stored in the EFI system table so it can be accessed later.
140 VariableInfo.efi can dump out the table. Only Boot Services variable
141 accesses are tracked by this code. The PcdVariableCollectStatistics
142 build flag controls if this feature is enabled.
144 A read that hits in the cache will have Read and Cache true for
145 the transaction. Data is allocated by this routine, but never
148 @param[in] VariableName Name of the Variable to track.
149 @param[in] VendorGuid Guid of the Variable to track.
150 @param[in] Volatile TRUE if volatile FALSE if non-volatile.
151 @param[in] Read TRUE if GetVariable() was called.
152 @param[in] Write TRUE if SetVariable() was called.
153 @param[in] Delete TRUE if deleted via SetVariable().
154 @param[in] Cache TRUE for a cache hit.
159 IN CHAR16
*VariableName
,
160 IN EFI_GUID
*VendorGuid
,
168 VARIABLE_INFO_ENTRY
*Entry
;
170 if (FeaturePcdGet (PcdVariableCollectStatistics
)) {
173 // Don't collect statistics at runtime.
177 if (gVariableInfo
== NULL
) {
179 // On the first call allocate a entry and place a pointer to it in
180 // the EFI System Table.
182 gVariableInfo
= AllocateZeroPool (sizeof (VARIABLE_INFO_ENTRY
));
183 ASSERT (gVariableInfo
!= NULL
);
185 CopyGuid (&gVariableInfo
->VendorGuid
, VendorGuid
);
186 gVariableInfo
->Name
= AllocateZeroPool (StrSize (VariableName
));
187 ASSERT (gVariableInfo
->Name
!= NULL
);
188 StrCpyS (gVariableInfo
->Name
, StrSize(VariableName
)/sizeof(CHAR16
), VariableName
);
189 gVariableInfo
->Volatile
= Volatile
;
193 for (Entry
= gVariableInfo
; Entry
!= NULL
; Entry
= Entry
->Next
) {
194 if (CompareGuid (VendorGuid
, &Entry
->VendorGuid
)) {
195 if (StrCmp (VariableName
, Entry
->Name
) == 0) {
203 Entry
->DeleteCount
++;
213 if (Entry
->Next
== NULL
) {
215 // If the entry is not in the table add it.
216 // Next iteration of the loop will fill in the data.
218 Entry
->Next
= AllocateZeroPool (sizeof (VARIABLE_INFO_ENTRY
));
219 ASSERT (Entry
->Next
!= NULL
);
221 CopyGuid (&Entry
->Next
->VendorGuid
, VendorGuid
);
222 Entry
->Next
->Name
= AllocateZeroPool (StrSize (VariableName
));
223 ASSERT (Entry
->Next
->Name
!= NULL
);
224 StrCpyS (Entry
->Next
->Name
, StrSize(VariableName
)/sizeof(CHAR16
), VariableName
);
225 Entry
->Next
->Volatile
= Volatile
;
235 This code checks if variable header is valid or not.
237 @param Variable Pointer to the Variable Header.
238 @param VariableStoreEnd Pointer to the Variable Store End.
240 @retval TRUE Variable header is valid.
241 @retval FALSE Variable header is not valid.
245 IsValidVariableHeader (
246 IN VARIABLE_HEADER
*Variable
,
247 IN VARIABLE_HEADER
*VariableStoreEnd
250 if ((Variable
== NULL
) || (Variable
>= VariableStoreEnd
) || (Variable
->StartId
!= VARIABLE_DATA
)) {
252 // Variable is NULL or has reached the end of variable store,
253 // or the StartId is not correct.
264 This function writes data to the FWH at the correct LBA even if the LBAs
267 @param Global Pointer to VARAIBLE_GLOBAL structure.
268 @param Volatile Point out the Variable is Volatile or Non-Volatile.
269 @param SetByIndex TRUE if target pointer is given as index.
270 FALSE if target pointer is absolute.
271 @param Fvb Pointer to the writable FVB protocol.
272 @param DataPtrIndex Pointer to the Data from the end of VARIABLE_STORE_HEADER
274 @param DataSize Size of data to be written.
275 @param Buffer Pointer to the buffer from which data is written.
277 @retval EFI_INVALID_PARAMETER Parameters not valid.
278 @retval EFI_SUCCESS Variable store successfully updated.
282 UpdateVariableStore (
283 IN VARIABLE_GLOBAL
*Global
,
285 IN BOOLEAN SetByIndex
,
286 IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*Fvb
,
287 IN UINTN DataPtrIndex
,
292 EFI_FV_BLOCK_MAP_ENTRY
*PtrBlockMapEntry
;
300 EFI_FIRMWARE_VOLUME_HEADER
*FwVolHeader
;
301 VARIABLE_STORE_HEADER
*VolatileBase
;
302 EFI_PHYSICAL_ADDRESS FvVolHdr
;
303 EFI_PHYSICAL_ADDRESS DataPtr
;
307 DataPtr
= DataPtrIndex
;
310 // Check if the Data is Volatile.
314 return EFI_INVALID_PARAMETER
;
316 Status
= Fvb
->GetPhysicalAddress(Fvb
, &FvVolHdr
);
317 ASSERT_EFI_ERROR (Status
);
319 FwVolHeader
= (EFI_FIRMWARE_VOLUME_HEADER
*) ((UINTN
) FvVolHdr
);
321 // Data Pointer should point to the actual Address where data is to be
325 DataPtr
+= mVariableModuleGlobal
->VariableGlobal
.NonVolatileVariableBase
;
328 if ((DataPtr
+ DataSize
) >= ((EFI_PHYSICAL_ADDRESS
) (UINTN
) ((UINT8
*) FwVolHeader
+ FwVolHeader
->FvLength
))) {
329 return EFI_INVALID_PARAMETER
;
333 // Data Pointer should point to the actual Address where data is to be
336 VolatileBase
= (VARIABLE_STORE_HEADER
*) ((UINTN
) mVariableModuleGlobal
->VariableGlobal
.VolatileVariableBase
);
338 DataPtr
+= mVariableModuleGlobal
->VariableGlobal
.VolatileVariableBase
;
341 if ((DataPtr
+ DataSize
) >= ((UINTN
) ((UINT8
*) VolatileBase
+ VolatileBase
->Size
))) {
342 return EFI_INVALID_PARAMETER
;
346 // If Volatile Variable just do a simple mem copy.
348 CopyMem ((UINT8
*)(UINTN
)DataPtr
, Buffer
, DataSize
);
353 // If we are here we are dealing with Non-Volatile Variables.
355 LinearOffset
= (UINTN
) FwVolHeader
;
356 CurrWritePtr
= (UINTN
) DataPtr
;
357 CurrWriteSize
= DataSize
;
361 if (CurrWritePtr
< LinearOffset
) {
362 return EFI_INVALID_PARAMETER
;
365 for (PtrBlockMapEntry
= mNvFvHeaderCache
->BlockMap
; PtrBlockMapEntry
->NumBlocks
!= 0; PtrBlockMapEntry
++) {
366 for (BlockIndex2
= 0; BlockIndex2
< PtrBlockMapEntry
->NumBlocks
; BlockIndex2
++) {
368 // Check to see if the Variable Writes are spanning through multiple
371 if ((CurrWritePtr
>= LinearOffset
) && (CurrWritePtr
< LinearOffset
+ PtrBlockMapEntry
->Length
)) {
372 if ((CurrWritePtr
+ CurrWriteSize
) <= (LinearOffset
+ PtrBlockMapEntry
->Length
)) {
373 Status
= Fvb
->Write (
376 (UINTN
) (CurrWritePtr
- LinearOffset
),
382 Size
= (UINT32
) (LinearOffset
+ PtrBlockMapEntry
->Length
- CurrWritePtr
);
383 Status
= Fvb
->Write (
386 (UINTN
) (CurrWritePtr
- LinearOffset
),
390 if (EFI_ERROR (Status
)) {
394 CurrWritePtr
= LinearOffset
+ PtrBlockMapEntry
->Length
;
395 CurrBuffer
= CurrBuffer
+ Size
;
396 CurrWriteSize
= CurrWriteSize
- Size
;
400 LinearOffset
+= PtrBlockMapEntry
->Length
;
411 This code gets the current status of Variable Store.
413 @param VarStoreHeader Pointer to the Variable Store Header.
415 @retval EfiRaw Variable store status is raw.
416 @retval EfiValid Variable store status is valid.
417 @retval EfiInvalid Variable store status is invalid.
420 VARIABLE_STORE_STATUS
421 GetVariableStoreStatus (
422 IN VARIABLE_STORE_HEADER
*VarStoreHeader
425 if ((CompareGuid (&VarStoreHeader
->Signature
, &gEfiAuthenticatedVariableGuid
) ||
426 CompareGuid (&VarStoreHeader
->Signature
, &gEfiVariableGuid
)) &&
427 VarStoreHeader
->Format
== VARIABLE_STORE_FORMATTED
&&
428 VarStoreHeader
->State
== VARIABLE_STORE_HEALTHY
432 } else if (((UINT32
*)(&VarStoreHeader
->Signature
))[0] == 0xffffffff &&
433 ((UINT32
*)(&VarStoreHeader
->Signature
))[1] == 0xffffffff &&
434 ((UINT32
*)(&VarStoreHeader
->Signature
))[2] == 0xffffffff &&
435 ((UINT32
*)(&VarStoreHeader
->Signature
))[3] == 0xffffffff &&
436 VarStoreHeader
->Size
== 0xffffffff &&
437 VarStoreHeader
->Format
== 0xff &&
438 VarStoreHeader
->State
== 0xff
448 This code gets the size of variable header.
450 @return Size of variable header in bytes in type UINTN.
454 GetVariableHeaderSize (
460 if (mVariableModuleGlobal
->VariableGlobal
.AuthFormat
) {
461 Value
= sizeof (AUTHENTICATED_VARIABLE_HEADER
);
463 Value
= sizeof (VARIABLE_HEADER
);
471 This code gets the size of name of variable.
473 @param Variable Pointer to the Variable Header.
475 @return UINTN Size of variable in bytes.
480 IN VARIABLE_HEADER
*Variable
483 AUTHENTICATED_VARIABLE_HEADER
*AuthVariable
;
485 AuthVariable
= (AUTHENTICATED_VARIABLE_HEADER
*) Variable
;
486 if (mVariableModuleGlobal
->VariableGlobal
.AuthFormat
) {
487 if (AuthVariable
->State
== (UINT8
) (-1) ||
488 AuthVariable
->DataSize
== (UINT32
) (-1) ||
489 AuthVariable
->NameSize
== (UINT32
) (-1) ||
490 AuthVariable
->Attributes
== (UINT32
) (-1)) {
493 return (UINTN
) AuthVariable
->NameSize
;
495 if (Variable
->State
== (UINT8
) (-1) ||
496 Variable
->DataSize
== (UINT32
) (-1) ||
497 Variable
->NameSize
== (UINT32
) (-1) ||
498 Variable
->Attributes
== (UINT32
) (-1)) {
501 return (UINTN
) Variable
->NameSize
;
506 This code sets the size of name of variable.
508 @param[in] Variable Pointer to the Variable Header.
509 @param[in] NameSize Name size to set.
513 SetNameSizeOfVariable (
514 IN VARIABLE_HEADER
*Variable
,
518 AUTHENTICATED_VARIABLE_HEADER
*AuthVariable
;
520 AuthVariable
= (AUTHENTICATED_VARIABLE_HEADER
*) Variable
;
521 if (mVariableModuleGlobal
->VariableGlobal
.AuthFormat
) {
522 AuthVariable
->NameSize
= (UINT32
) NameSize
;
524 Variable
->NameSize
= (UINT32
) NameSize
;
530 This code gets the size of variable data.
532 @param Variable Pointer to the Variable Header.
534 @return Size of variable in bytes.
539 IN VARIABLE_HEADER
*Variable
542 AUTHENTICATED_VARIABLE_HEADER
*AuthVariable
;
544 AuthVariable
= (AUTHENTICATED_VARIABLE_HEADER
*) Variable
;
545 if (mVariableModuleGlobal
->VariableGlobal
.AuthFormat
) {
546 if (AuthVariable
->State
== (UINT8
) (-1) ||
547 AuthVariable
->DataSize
== (UINT32
) (-1) ||
548 AuthVariable
->NameSize
== (UINT32
) (-1) ||
549 AuthVariable
->Attributes
== (UINT32
) (-1)) {
552 return (UINTN
) AuthVariable
->DataSize
;
554 if (Variable
->State
== (UINT8
) (-1) ||
555 Variable
->DataSize
== (UINT32
) (-1) ||
556 Variable
->NameSize
== (UINT32
) (-1) ||
557 Variable
->Attributes
== (UINT32
) (-1)) {
560 return (UINTN
) Variable
->DataSize
;
565 This code sets the size of variable data.
567 @param[in] Variable Pointer to the Variable Header.
568 @param[in] DataSize Data size to set.
572 SetDataSizeOfVariable (
573 IN VARIABLE_HEADER
*Variable
,
577 AUTHENTICATED_VARIABLE_HEADER
*AuthVariable
;
579 AuthVariable
= (AUTHENTICATED_VARIABLE_HEADER
*) Variable
;
580 if (mVariableModuleGlobal
->VariableGlobal
.AuthFormat
) {
581 AuthVariable
->DataSize
= (UINT32
) DataSize
;
583 Variable
->DataSize
= (UINT32
) DataSize
;
589 This code gets the pointer to the variable name.
591 @param Variable Pointer to the Variable Header.
593 @return Pointer to Variable Name which is Unicode encoding.
598 IN VARIABLE_HEADER
*Variable
601 return (CHAR16
*) ((UINTN
) Variable
+ GetVariableHeaderSize ());
605 This code gets the pointer to the variable guid.
607 @param Variable Pointer to the Variable Header.
609 @return A EFI_GUID* pointer to Vendor Guid.
614 IN VARIABLE_HEADER
*Variable
617 AUTHENTICATED_VARIABLE_HEADER
*AuthVariable
;
619 AuthVariable
= (AUTHENTICATED_VARIABLE_HEADER
*) Variable
;
620 if (mVariableModuleGlobal
->VariableGlobal
.AuthFormat
) {
621 return &AuthVariable
->VendorGuid
;
623 return &Variable
->VendorGuid
;
629 This code gets the pointer to the variable data.
631 @param Variable Pointer to the Variable Header.
633 @return Pointer to Variable Data.
638 IN VARIABLE_HEADER
*Variable
644 // Be careful about pad size for alignment.
646 Value
= (UINTN
) GetVariableNamePtr (Variable
);
647 Value
+= NameSizeOfVariable (Variable
);
648 Value
+= GET_PAD_SIZE (NameSizeOfVariable (Variable
));
650 return (UINT8
*) Value
;
654 This code gets the variable data offset related to variable header.
656 @param Variable Pointer to the Variable Header.
658 @return Variable Data offset.
662 GetVariableDataOffset (
663 IN VARIABLE_HEADER
*Variable
669 // Be careful about pad size for alignment
671 Value
= GetVariableHeaderSize ();
672 Value
+= NameSizeOfVariable (Variable
);
673 Value
+= GET_PAD_SIZE (NameSizeOfVariable (Variable
));
680 This code gets the pointer to the next variable header.
682 @param Variable Pointer to the Variable Header.
684 @return Pointer to next variable header.
689 IN VARIABLE_HEADER
*Variable
694 Value
= (UINTN
) GetVariableDataPtr (Variable
);
695 Value
+= DataSizeOfVariable (Variable
);
696 Value
+= GET_PAD_SIZE (DataSizeOfVariable (Variable
));
699 // Be careful about pad size for alignment.
701 return (VARIABLE_HEADER
*) HEADER_ALIGN (Value
);
706 Gets the pointer to the first variable header in given variable store area.
708 @param VarStoreHeader Pointer to the Variable Store Header.
710 @return Pointer to the first variable header.
715 IN VARIABLE_STORE_HEADER
*VarStoreHeader
719 // The end of variable store.
721 return (VARIABLE_HEADER
*) HEADER_ALIGN (VarStoreHeader
+ 1);
726 Gets the pointer to the end of the variable storage area.
728 This function gets pointer to the end of the variable storage
729 area, according to the input variable store header.
731 @param VarStoreHeader Pointer to the Variable Store Header.
733 @return Pointer to the end of the variable storage area.
738 IN VARIABLE_STORE_HEADER
*VarStoreHeader
742 // The end of variable store
744 return (VARIABLE_HEADER
*) HEADER_ALIGN ((UINTN
) VarStoreHeader
+ VarStoreHeader
->Size
);
748 Record variable error flag.
750 @param[in] Flag Variable error flag to record.
751 @param[in] VariableName Name of variable.
752 @param[in] VendorGuid Guid of variable.
753 @param[in] Attributes Attributes of the variable.
754 @param[in] VariableSize Size of the variable.
759 IN VAR_ERROR_FLAG Flag
,
760 IN CHAR16
*VariableName
,
761 IN EFI_GUID
*VendorGuid
,
762 IN UINT32 Attributes
,
763 IN UINTN VariableSize
767 VARIABLE_POINTER_TRACK Variable
;
768 VAR_ERROR_FLAG
*VarErrFlag
;
769 VAR_ERROR_FLAG TempFlag
;
772 DEBUG ((EFI_D_ERROR
, "RecordVarErrorFlag (0x%02x) %s:%g - 0x%08x - 0x%x\n", Flag
, VariableName
, VendorGuid
, Attributes
, VariableSize
));
773 if (Flag
== VAR_ERROR_FLAG_SYSTEM_ERROR
) {
775 DEBUG ((EFI_D_ERROR
, "CommonRuntimeVariableSpace = 0x%x - CommonVariableTotalSize = 0x%x\n", mVariableModuleGlobal
->CommonRuntimeVariableSpace
, mVariableModuleGlobal
->CommonVariableTotalSize
));
777 DEBUG ((EFI_D_ERROR
, "CommonVariableSpace = 0x%x - CommonVariableTotalSize = 0x%x\n", mVariableModuleGlobal
->CommonVariableSpace
, mVariableModuleGlobal
->CommonVariableTotalSize
));
780 DEBUG ((EFI_D_ERROR
, "CommonMaxUserVariableSpace = 0x%x - CommonUserVariableTotalSize = 0x%x\n", mVariableModuleGlobal
->CommonMaxUserVariableSpace
, mVariableModuleGlobal
->CommonUserVariableTotalSize
));
786 // Before EndOfDxe, just record the current boot variable error flag to local variable,
787 // and leave the variable error flag in NV flash as the last boot variable error flag.
788 // After EndOfDxe in InitializeVarErrorFlag (), the variable error flag in NV flash
789 // will be initialized to this local current boot variable error flag.
791 mCurrentBootVarErrFlag
&= Flag
;
796 // Record error flag (it should have be initialized).
798 Status
= FindVariable (
800 &gEdkiiVarErrorFlagGuid
,
802 &mVariableModuleGlobal
->VariableGlobal
,
805 if (!EFI_ERROR (Status
)) {
806 VarErrFlag
= (VAR_ERROR_FLAG
*) GetVariableDataPtr (Variable
.CurrPtr
);
807 TempFlag
= *VarErrFlag
;
809 if (TempFlag
== *VarErrFlag
) {
812 Status
= UpdateVariableStore (
813 &mVariableModuleGlobal
->VariableGlobal
,
816 mVariableModuleGlobal
->FvbInstance
,
817 (UINTN
) VarErrFlag
- (UINTN
) mNvVariableCache
+ (UINTN
) mVariableModuleGlobal
->VariableGlobal
.NonVolatileVariableBase
,
821 if (!EFI_ERROR (Status
)) {
823 // Update the data in NV cache.
825 *VarErrFlag
= TempFlag
;
831 Initialize variable error flag.
833 Before EndOfDxe, the variable indicates the last boot variable error flag,
834 then it means the last boot variable error flag must be got before EndOfDxe.
835 After EndOfDxe, the variable indicates the current boot variable error flag,
836 then it means the current boot variable error flag must be got after EndOfDxe.
840 InitializeVarErrorFlag (
845 VARIABLE_POINTER_TRACK Variable
;
847 VAR_ERROR_FLAG VarErrFlag
;
853 Flag
= mCurrentBootVarErrFlag
;
854 DEBUG ((EFI_D_INFO
, "Initialize variable error flag (%02x)\n", Flag
));
856 Status
= FindVariable (
858 &gEdkiiVarErrorFlagGuid
,
860 &mVariableModuleGlobal
->VariableGlobal
,
863 if (!EFI_ERROR (Status
)) {
864 VarErrFlag
= *((VAR_ERROR_FLAG
*) GetVariableDataPtr (Variable
.CurrPtr
));
865 if (VarErrFlag
== Flag
) {
872 &gEdkiiVarErrorFlagGuid
,
875 VARIABLE_ATTRIBUTE_NV_BS_RT
,
886 @param[in] Variable Pointer to variable header.
888 @retval TRUE User variable.
889 @retval FALSE System variable.
894 IN VARIABLE_HEADER
*Variable
897 VAR_CHECK_VARIABLE_PROPERTY Property
;
900 // Only after End Of Dxe, the variables belong to system variable are fixed.
901 // If PcdMaxUserNvStorageVariableSize is 0, it means user variable share the same NV storage with system variable,
902 // then no need to check if the variable is user variable or not specially.
904 if (mEndOfDxe
&& (mVariableModuleGlobal
->CommonMaxUserVariableSpace
!= mVariableModuleGlobal
->CommonVariableSpace
)) {
905 if (VarCheckLibVariablePropertyGet (GetVariableNamePtr (Variable
), GetVendorGuidPtr (Variable
), &Property
) == EFI_NOT_FOUND
) {
913 Calculate common user variable total size.
917 CalculateCommonUserVariableTotalSize (
921 VARIABLE_HEADER
*Variable
;
922 VARIABLE_HEADER
*NextVariable
;
924 VAR_CHECK_VARIABLE_PROPERTY Property
;
927 // Only after End Of Dxe, the variables belong to system variable are fixed.
928 // If PcdMaxUserNvStorageVariableSize is 0, it means user variable share the same NV storage with system variable,
929 // then no need to calculate the common user variable total size specially.
931 if (mEndOfDxe
&& (mVariableModuleGlobal
->CommonMaxUserVariableSpace
!= mVariableModuleGlobal
->CommonVariableSpace
)) {
932 Variable
= GetStartPointer (mNvVariableCache
);
933 while (IsValidVariableHeader (Variable
, GetEndPointer (mNvVariableCache
))) {
934 NextVariable
= GetNextVariablePtr (Variable
);
935 VariableSize
= (UINTN
) NextVariable
- (UINTN
) Variable
;
936 if ((Variable
->Attributes
& EFI_VARIABLE_HARDWARE_ERROR_RECORD
) != EFI_VARIABLE_HARDWARE_ERROR_RECORD
) {
937 if (VarCheckLibVariablePropertyGet (GetVariableNamePtr (Variable
), GetVendorGuidPtr (Variable
), &Property
) == EFI_NOT_FOUND
) {
939 // No property, it is user variable.
941 mVariableModuleGlobal
->CommonUserVariableTotalSize
+= VariableSize
;
945 Variable
= NextVariable
;
951 Initialize variable quota.
955 InitializeVariableQuota (
963 InitializeVarErrorFlag ();
964 CalculateCommonUserVariableTotalSize ();
969 Variable store garbage collection and reclaim operation.
971 @param[in] VariableBase Base address of variable store.
972 @param[out] LastVariableOffset Offset of last variable.
973 @param[in] IsVolatile The variable store is volatile or not;
974 if it is non-volatile, need FTW.
975 @param[in, out] UpdatingPtrTrack Pointer to updating variable pointer track structure.
976 @param[in] NewVariable Pointer to new variable.
977 @param[in] NewVariableSize New variable size.
979 @return EFI_SUCCESS Reclaim operation has finished successfully.
980 @return EFI_OUT_OF_RESOURCES No enough memory resources or variable space.
981 @return Others Unexpect error happened during reclaim operation.
986 IN EFI_PHYSICAL_ADDRESS VariableBase
,
987 OUT UINTN
*LastVariableOffset
,
988 IN BOOLEAN IsVolatile
,
989 IN OUT VARIABLE_POINTER_TRACK
*UpdatingPtrTrack
,
990 IN VARIABLE_HEADER
*NewVariable
,
991 IN UINTN NewVariableSize
994 VARIABLE_HEADER
*Variable
;
995 VARIABLE_HEADER
*AddedVariable
;
996 VARIABLE_HEADER
*NextVariable
;
997 VARIABLE_HEADER
*NextAddedVariable
;
998 VARIABLE_STORE_HEADER
*VariableStoreHeader
;
1000 UINTN MaximumBufferSize
;
1008 UINTN CommonVariableTotalSize
;
1009 UINTN CommonUserVariableTotalSize
;
1010 UINTN HwErrVariableTotalSize
;
1011 VARIABLE_HEADER
*UpdatingVariable
;
1012 VARIABLE_HEADER
*UpdatingInDeletedTransition
;
1014 UpdatingVariable
= NULL
;
1015 UpdatingInDeletedTransition
= NULL
;
1016 if (UpdatingPtrTrack
!= NULL
) {
1017 UpdatingVariable
= UpdatingPtrTrack
->CurrPtr
;
1018 UpdatingInDeletedTransition
= UpdatingPtrTrack
->InDeletedTransitionPtr
;
1021 VariableStoreHeader
= (VARIABLE_STORE_HEADER
*) ((UINTN
) VariableBase
);
1023 CommonVariableTotalSize
= 0;
1024 CommonUserVariableTotalSize
= 0;
1025 HwErrVariableTotalSize
= 0;
1029 // Start Pointers for the variable.
1031 Variable
= GetStartPointer (VariableStoreHeader
);
1032 MaximumBufferSize
= sizeof (VARIABLE_STORE_HEADER
);
1034 while (IsValidVariableHeader (Variable
, GetEndPointer (VariableStoreHeader
))) {
1035 NextVariable
= GetNextVariablePtr (Variable
);
1036 if ((Variable
->State
== VAR_ADDED
|| Variable
->State
== (VAR_IN_DELETED_TRANSITION
& VAR_ADDED
)) &&
1037 Variable
!= UpdatingVariable
&&
1038 Variable
!= UpdatingInDeletedTransition
1040 VariableSize
= (UINTN
) NextVariable
- (UINTN
) Variable
;
1041 MaximumBufferSize
+= VariableSize
;
1044 Variable
= NextVariable
;
1047 if (NewVariable
!= NULL
) {
1049 // Add the new variable size.
1051 MaximumBufferSize
+= NewVariableSize
;
1055 // Reserve the 1 Bytes with Oxff to identify the
1056 // end of the variable buffer.
1058 MaximumBufferSize
+= 1;
1059 ValidBuffer
= AllocatePool (MaximumBufferSize
);
1060 if (ValidBuffer
== NULL
) {
1061 return EFI_OUT_OF_RESOURCES
;
1065 // For NV variable reclaim, don't allocate pool here and just use mNvVariableCache
1066 // as the buffer to reduce SMRAM consumption for SMM variable driver.
1068 MaximumBufferSize
= mNvVariableCache
->Size
;
1069 ValidBuffer
= (UINT8
*) mNvVariableCache
;
1072 SetMem (ValidBuffer
, MaximumBufferSize
, 0xff);
1075 // Copy variable store header.
1077 CopyMem (ValidBuffer
, VariableStoreHeader
, sizeof (VARIABLE_STORE_HEADER
));
1078 CurrPtr
= (UINT8
*) GetStartPointer ((VARIABLE_STORE_HEADER
*) ValidBuffer
);
1081 // Reinstall all ADDED variables as long as they are not identical to Updating Variable.
1083 Variable
= GetStartPointer (VariableStoreHeader
);
1084 while (IsValidVariableHeader (Variable
, GetEndPointer (VariableStoreHeader
))) {
1085 NextVariable
= GetNextVariablePtr (Variable
);
1086 if (Variable
!= UpdatingVariable
&& Variable
->State
== VAR_ADDED
) {
1087 VariableSize
= (UINTN
) NextVariable
- (UINTN
) Variable
;
1088 CopyMem (CurrPtr
, (UINT8
*) Variable
, VariableSize
);
1089 CurrPtr
+= VariableSize
;
1090 if ((!IsVolatile
) && ((Variable
->Attributes
& EFI_VARIABLE_HARDWARE_ERROR_RECORD
) == EFI_VARIABLE_HARDWARE_ERROR_RECORD
)) {
1091 HwErrVariableTotalSize
+= VariableSize
;
1092 } else if ((!IsVolatile
) && ((Variable
->Attributes
& EFI_VARIABLE_HARDWARE_ERROR_RECORD
) != EFI_VARIABLE_HARDWARE_ERROR_RECORD
)) {
1093 CommonVariableTotalSize
+= VariableSize
;
1094 if (IsUserVariable (Variable
)) {
1095 CommonUserVariableTotalSize
+= VariableSize
;
1099 Variable
= NextVariable
;
1103 // Reinstall all in delete transition variables.
1105 Variable
= GetStartPointer (VariableStoreHeader
);
1106 while (IsValidVariableHeader (Variable
, GetEndPointer (VariableStoreHeader
))) {
1107 NextVariable
= GetNextVariablePtr (Variable
);
1108 if (Variable
!= UpdatingVariable
&& Variable
!= UpdatingInDeletedTransition
&& Variable
->State
== (VAR_IN_DELETED_TRANSITION
& VAR_ADDED
)) {
1111 // Buffer has cached all ADDED variable.
1112 // Per IN_DELETED variable, we have to guarantee that
1113 // no ADDED one in previous buffer.
1117 AddedVariable
= GetStartPointer ((VARIABLE_STORE_HEADER
*) ValidBuffer
);
1118 while (IsValidVariableHeader (AddedVariable
, GetEndPointer ((VARIABLE_STORE_HEADER
*) ValidBuffer
))) {
1119 NextAddedVariable
= GetNextVariablePtr (AddedVariable
);
1120 NameSize
= NameSizeOfVariable (AddedVariable
);
1121 if (CompareGuid (GetVendorGuidPtr (AddedVariable
), GetVendorGuidPtr (Variable
)) &&
1122 NameSize
== NameSizeOfVariable (Variable
)
1124 Point0
= (VOID
*) GetVariableNamePtr (AddedVariable
);
1125 Point1
= (VOID
*) GetVariableNamePtr (Variable
);
1126 if (CompareMem (Point0
, Point1
, NameSize
) == 0) {
1131 AddedVariable
= NextAddedVariable
;
1135 // Promote VAR_IN_DELETED_TRANSITION to VAR_ADDED.
1137 VariableSize
= (UINTN
) NextVariable
- (UINTN
) Variable
;
1138 CopyMem (CurrPtr
, (UINT8
*) Variable
, VariableSize
);
1139 ((VARIABLE_HEADER
*) CurrPtr
)->State
= VAR_ADDED
;
1140 CurrPtr
+= VariableSize
;
1141 if ((!IsVolatile
) && ((Variable
->Attributes
& EFI_VARIABLE_HARDWARE_ERROR_RECORD
) == EFI_VARIABLE_HARDWARE_ERROR_RECORD
)) {
1142 HwErrVariableTotalSize
+= VariableSize
;
1143 } else if ((!IsVolatile
) && ((Variable
->Attributes
& EFI_VARIABLE_HARDWARE_ERROR_RECORD
) != EFI_VARIABLE_HARDWARE_ERROR_RECORD
)) {
1144 CommonVariableTotalSize
+= VariableSize
;
1145 if (IsUserVariable (Variable
)) {
1146 CommonUserVariableTotalSize
+= VariableSize
;
1152 Variable
= NextVariable
;
1156 // Install the new variable if it is not NULL.
1158 if (NewVariable
!= NULL
) {
1159 if (((UINTN
) CurrPtr
- (UINTN
) ValidBuffer
) + NewVariableSize
> VariableStoreHeader
->Size
) {
1161 // No enough space to store the new variable.
1163 Status
= EFI_OUT_OF_RESOURCES
;
1167 if ((NewVariable
->Attributes
& EFI_VARIABLE_HARDWARE_ERROR_RECORD
) == EFI_VARIABLE_HARDWARE_ERROR_RECORD
) {
1168 HwErrVariableTotalSize
+= NewVariableSize
;
1169 } else if ((NewVariable
->Attributes
& EFI_VARIABLE_HARDWARE_ERROR_RECORD
) != EFI_VARIABLE_HARDWARE_ERROR_RECORD
) {
1170 CommonVariableTotalSize
+= NewVariableSize
;
1171 if (IsUserVariable (NewVariable
)) {
1172 CommonUserVariableTotalSize
+= NewVariableSize
;
1175 if ((HwErrVariableTotalSize
> PcdGet32 (PcdHwErrStorageSize
)) ||
1176 (CommonVariableTotalSize
> mVariableModuleGlobal
->CommonVariableSpace
) ||
1177 (CommonUserVariableTotalSize
> mVariableModuleGlobal
->CommonMaxUserVariableSpace
)) {
1179 // No enough space to store the new variable by NV or NV+HR attribute.
1181 Status
= EFI_OUT_OF_RESOURCES
;
1186 CopyMem (CurrPtr
, (UINT8
*) NewVariable
, NewVariableSize
);
1187 ((VARIABLE_HEADER
*) CurrPtr
)->State
= VAR_ADDED
;
1188 if (UpdatingVariable
!= NULL
) {
1189 UpdatingPtrTrack
->CurrPtr
= (VARIABLE_HEADER
*)((UINTN
)UpdatingPtrTrack
->StartPtr
+ ((UINTN
)CurrPtr
- (UINTN
)GetStartPointer ((VARIABLE_STORE_HEADER
*) ValidBuffer
)));
1190 UpdatingPtrTrack
->InDeletedTransitionPtr
= NULL
;
1192 CurrPtr
+= NewVariableSize
;
1197 // If volatile variable store, just copy valid buffer.
1199 SetMem ((UINT8
*) (UINTN
) VariableBase
, VariableStoreHeader
->Size
, 0xff);
1200 CopyMem ((UINT8
*) (UINTN
) VariableBase
, ValidBuffer
, (UINTN
) CurrPtr
- (UINTN
) ValidBuffer
);
1201 *LastVariableOffset
= (UINTN
) CurrPtr
- (UINTN
) ValidBuffer
;
1202 Status
= EFI_SUCCESS
;
1205 // If non-volatile variable store, perform FTW here.
1207 Status
= FtwVariableSpace (
1209 (VARIABLE_STORE_HEADER
*) ValidBuffer
1211 if (!EFI_ERROR (Status
)) {
1212 *LastVariableOffset
= (UINTN
) CurrPtr
- (UINTN
) ValidBuffer
;
1213 mVariableModuleGlobal
->HwErrVariableTotalSize
= HwErrVariableTotalSize
;
1214 mVariableModuleGlobal
->CommonVariableTotalSize
= CommonVariableTotalSize
;
1215 mVariableModuleGlobal
->CommonUserVariableTotalSize
= CommonUserVariableTotalSize
;
1217 mVariableModuleGlobal
->HwErrVariableTotalSize
= 0;
1218 mVariableModuleGlobal
->CommonVariableTotalSize
= 0;
1219 mVariableModuleGlobal
->CommonUserVariableTotalSize
= 0;
1220 Variable
= GetStartPointer ((VARIABLE_STORE_HEADER
*)(UINTN
)VariableBase
);
1221 while (IsValidVariableHeader (Variable
, GetEndPointer ((VARIABLE_STORE_HEADER
*)(UINTN
)VariableBase
))) {
1222 NextVariable
= GetNextVariablePtr (Variable
);
1223 VariableSize
= (UINTN
) NextVariable
- (UINTN
) Variable
;
1224 if ((Variable
->Attributes
& EFI_VARIABLE_HARDWARE_ERROR_RECORD
) == EFI_VARIABLE_HARDWARE_ERROR_RECORD
) {
1225 mVariableModuleGlobal
->HwErrVariableTotalSize
+= VariableSize
;
1226 } else if ((Variable
->Attributes
& EFI_VARIABLE_HARDWARE_ERROR_RECORD
) != EFI_VARIABLE_HARDWARE_ERROR_RECORD
) {
1227 mVariableModuleGlobal
->CommonVariableTotalSize
+= VariableSize
;
1228 if (IsUserVariable (Variable
)) {
1229 mVariableModuleGlobal
->CommonUserVariableTotalSize
+= VariableSize
;
1233 Variable
= NextVariable
;
1235 *LastVariableOffset
= (UINTN
) Variable
- (UINTN
) VariableBase
;
1241 FreePool (ValidBuffer
);
1244 // For NV variable reclaim, we use mNvVariableCache as the buffer, so copy the data back.
1246 CopyMem (mNvVariableCache
, (UINT8
*)(UINTN
)VariableBase
, VariableStoreHeader
->Size
);
1253 Find the variable in the specified variable store.
1255 @param[in] VariableName Name of the variable to be found
1256 @param[in] VendorGuid Vendor GUID to be found.
1257 @param[in] IgnoreRtCheck Ignore EFI_VARIABLE_RUNTIME_ACCESS attribute
1258 check at runtime when searching variable.
1259 @param[in, out] PtrTrack Variable Track Pointer structure that contains Variable Information.
1261 @retval EFI_SUCCESS Variable found successfully
1262 @retval EFI_NOT_FOUND Variable not found
1266 IN CHAR16
*VariableName
,
1267 IN EFI_GUID
*VendorGuid
,
1268 IN BOOLEAN IgnoreRtCheck
,
1269 IN OUT VARIABLE_POINTER_TRACK
*PtrTrack
1272 VARIABLE_HEADER
*InDeletedVariable
;
1275 PtrTrack
->InDeletedTransitionPtr
= NULL
;
1278 // Find the variable by walk through HOB, volatile and non-volatile variable store.
1280 InDeletedVariable
= NULL
;
1282 for ( PtrTrack
->CurrPtr
= PtrTrack
->StartPtr
1283 ; IsValidVariableHeader (PtrTrack
->CurrPtr
, PtrTrack
->EndPtr
)
1284 ; PtrTrack
->CurrPtr
= GetNextVariablePtr (PtrTrack
->CurrPtr
)
1286 if (PtrTrack
->CurrPtr
->State
== VAR_ADDED
||
1287 PtrTrack
->CurrPtr
->State
== (VAR_IN_DELETED_TRANSITION
& VAR_ADDED
)
1289 if (IgnoreRtCheck
|| !AtRuntime () || ((PtrTrack
->CurrPtr
->Attributes
& EFI_VARIABLE_RUNTIME_ACCESS
) != 0)) {
1290 if (VariableName
[0] == 0) {
1291 if (PtrTrack
->CurrPtr
->State
== (VAR_IN_DELETED_TRANSITION
& VAR_ADDED
)) {
1292 InDeletedVariable
= PtrTrack
->CurrPtr
;
1294 PtrTrack
->InDeletedTransitionPtr
= InDeletedVariable
;
1298 if (CompareGuid (VendorGuid
, GetVendorGuidPtr (PtrTrack
->CurrPtr
))) {
1299 Point
= (VOID
*) GetVariableNamePtr (PtrTrack
->CurrPtr
);
1301 ASSERT (NameSizeOfVariable (PtrTrack
->CurrPtr
) != 0);
1302 if (CompareMem (VariableName
, Point
, NameSizeOfVariable (PtrTrack
->CurrPtr
)) == 0) {
1303 if (PtrTrack
->CurrPtr
->State
== (VAR_IN_DELETED_TRANSITION
& VAR_ADDED
)) {
1304 InDeletedVariable
= PtrTrack
->CurrPtr
;
1306 PtrTrack
->InDeletedTransitionPtr
= InDeletedVariable
;
1316 PtrTrack
->CurrPtr
= InDeletedVariable
;
1317 return (PtrTrack
->CurrPtr
== NULL
) ? EFI_NOT_FOUND
: EFI_SUCCESS
;
1322 Finds variable in storage blocks of volatile and non-volatile storage areas.
1324 This code finds variable in storage blocks of volatile and non-volatile storage areas.
1325 If VariableName is an empty string, then we just return the first
1326 qualified variable without comparing VariableName and VendorGuid.
1327 If IgnoreRtCheck is TRUE, then we ignore the EFI_VARIABLE_RUNTIME_ACCESS attribute check
1328 at runtime when searching existing variable, only VariableName and VendorGuid are compared.
1329 Otherwise, variables without EFI_VARIABLE_RUNTIME_ACCESS are not visible at runtime.
1331 @param[in] VariableName Name of the variable to be found.
1332 @param[in] VendorGuid Vendor GUID to be found.
1333 @param[out] PtrTrack VARIABLE_POINTER_TRACK structure for output,
1334 including the range searched and the target position.
1335 @param[in] Global Pointer to VARIABLE_GLOBAL structure, including
1336 base of volatile variable storage area, base of
1337 NV variable storage area, and a lock.
1338 @param[in] IgnoreRtCheck Ignore EFI_VARIABLE_RUNTIME_ACCESS attribute
1339 check at runtime when searching variable.
1341 @retval EFI_INVALID_PARAMETER If VariableName is not an empty string, while
1343 @retval EFI_SUCCESS Variable successfully found.
1344 @retval EFI_NOT_FOUND Variable not found
1349 IN CHAR16
*VariableName
,
1350 IN EFI_GUID
*VendorGuid
,
1351 OUT VARIABLE_POINTER_TRACK
*PtrTrack
,
1352 IN VARIABLE_GLOBAL
*Global
,
1353 IN BOOLEAN IgnoreRtCheck
1357 VARIABLE_STORE_HEADER
*VariableStoreHeader
[VariableStoreTypeMax
];
1358 VARIABLE_STORE_TYPE Type
;
1360 if (VariableName
[0] != 0 && VendorGuid
== NULL
) {
1361 return EFI_INVALID_PARAMETER
;
1365 // 0: Volatile, 1: HOB, 2: Non-Volatile.
1366 // The index and attributes mapping must be kept in this order as RuntimeServiceGetNextVariableName
1367 // make use of this mapping to implement search algorithm.
1369 VariableStoreHeader
[VariableStoreTypeVolatile
] = (VARIABLE_STORE_HEADER
*) (UINTN
) Global
->VolatileVariableBase
;
1370 VariableStoreHeader
[VariableStoreTypeHob
] = (VARIABLE_STORE_HEADER
*) (UINTN
) Global
->HobVariableBase
;
1371 VariableStoreHeader
[VariableStoreTypeNv
] = mNvVariableCache
;
1374 // Find the variable by walk through HOB, volatile and non-volatile variable store.
1376 for (Type
= (VARIABLE_STORE_TYPE
) 0; Type
< VariableStoreTypeMax
; Type
++) {
1377 if (VariableStoreHeader
[Type
] == NULL
) {
1381 PtrTrack
->StartPtr
= GetStartPointer (VariableStoreHeader
[Type
]);
1382 PtrTrack
->EndPtr
= GetEndPointer (VariableStoreHeader
[Type
]);
1383 PtrTrack
->Volatile
= (BOOLEAN
) (Type
== VariableStoreTypeVolatile
);
1385 Status
= FindVariableEx (VariableName
, VendorGuid
, IgnoreRtCheck
, PtrTrack
);
1386 if (!EFI_ERROR (Status
)) {
1390 return EFI_NOT_FOUND
;
1394 Get index from supported language codes according to language string.
1396 This code is used to get corresponding index in supported language codes. It can handle
1397 RFC4646 and ISO639 language tags.
1398 In ISO639 language tags, take 3-characters as a delimitation to find matched string and calculate the index.
1399 In RFC4646 language tags, take semicolon as a delimitation to find matched string and calculate the index.
1402 SupportedLang = "engfraengfra"
1404 Iso639Language = TRUE
1405 The return value is "0".
1407 SupportedLang = "en;fr;en-US;fr-FR"
1409 Iso639Language = FALSE
1410 The return value is "3".
1412 @param SupportedLang Platform supported language codes.
1413 @param Lang Configured language.
1414 @param Iso639Language A bool value to signify if the handler is operated on ISO639 or RFC4646.
1416 @retval The index of language in the language codes.
1420 GetIndexFromSupportedLangCodes(
1421 IN CHAR8
*SupportedLang
,
1423 IN BOOLEAN Iso639Language
1427 UINTN CompareLength
;
1428 UINTN LanguageLength
;
1430 if (Iso639Language
) {
1431 CompareLength
= ISO_639_2_ENTRY_SIZE
;
1432 for (Index
= 0; Index
< AsciiStrLen (SupportedLang
); Index
+= CompareLength
) {
1433 if (AsciiStrnCmp (Lang
, SupportedLang
+ Index
, CompareLength
) == 0) {
1435 // Successfully find the index of Lang string in SupportedLang string.
1437 Index
= Index
/ CompareLength
;
1445 // Compare RFC4646 language code
1448 for (LanguageLength
= 0; Lang
[LanguageLength
] != '\0'; LanguageLength
++);
1450 for (Index
= 0; *SupportedLang
!= '\0'; Index
++, SupportedLang
+= CompareLength
) {
1452 // Skip ';' characters in SupportedLang
1454 for (; *SupportedLang
!= '\0' && *SupportedLang
== ';'; SupportedLang
++);
1456 // Determine the length of the next language code in SupportedLang
1458 for (CompareLength
= 0; SupportedLang
[CompareLength
] != '\0' && SupportedLang
[CompareLength
] != ';'; CompareLength
++);
1460 if ((CompareLength
== LanguageLength
) &&
1461 (AsciiStrnCmp (Lang
, SupportedLang
, CompareLength
) == 0)) {
1463 // Successfully find the index of Lang string in SupportedLang string.
1474 Get language string from supported language codes according to index.
1476 This code is used to get corresponding language strings in supported language codes. It can handle
1477 RFC4646 and ISO639 language tags.
1478 In ISO639 language tags, take 3-characters as a delimitation. Find language string according to the index.
1479 In RFC4646 language tags, take semicolon as a delimitation. Find language string according to the index.
1482 SupportedLang = "engfraengfra"
1484 Iso639Language = TRUE
1485 The return value is "fra".
1487 SupportedLang = "en;fr;en-US;fr-FR"
1489 Iso639Language = FALSE
1490 The return value is "fr".
1492 @param SupportedLang Platform supported language codes.
1493 @param Index The index in supported language codes.
1494 @param Iso639Language A bool value to signify if the handler is operated on ISO639 or RFC4646.
1496 @retval The language string in the language codes.
1500 GetLangFromSupportedLangCodes (
1501 IN CHAR8
*SupportedLang
,
1503 IN BOOLEAN Iso639Language
1507 UINTN CompareLength
;
1511 Supported
= SupportedLang
;
1512 if (Iso639Language
) {
1514 // According to the index of Lang string in SupportedLang string to get the language.
1515 // This code will be invoked in RUNTIME, therefore there is not a memory allocate/free operation.
1516 // In driver entry, it pre-allocates a runtime attribute memory to accommodate this string.
1518 CompareLength
= ISO_639_2_ENTRY_SIZE
;
1519 mVariableModuleGlobal
->Lang
[CompareLength
] = '\0';
1520 return CopyMem (mVariableModuleGlobal
->Lang
, SupportedLang
+ Index
* CompareLength
, CompareLength
);
1525 // Take semicolon as delimitation, sequentially traverse supported language codes.
1527 for (CompareLength
= 0; *Supported
!= ';' && *Supported
!= '\0'; CompareLength
++) {
1530 if ((*Supported
== '\0') && (SubIndex
!= Index
)) {
1532 // Have completed the traverse, but not find corrsponding string.
1533 // This case is not allowed to happen.
1538 if (SubIndex
== Index
) {
1540 // According to the index of Lang string in SupportedLang string to get the language.
1541 // As this code will be invoked in RUNTIME, therefore there is not memory allocate/free operation.
1542 // In driver entry, it pre-allocates a runtime attribute memory to accommodate this string.
1544 mVariableModuleGlobal
->PlatformLang
[CompareLength
] = '\0';
1545 return CopyMem (mVariableModuleGlobal
->PlatformLang
, Supported
- CompareLength
, CompareLength
);
1550 // Skip ';' characters in Supported
1552 for (; *Supported
!= '\0' && *Supported
== ';'; Supported
++);
1558 Returns a pointer to an allocated buffer that contains the best matching language
1559 from a set of supported languages.
1561 This function supports both ISO 639-2 and RFC 4646 language codes, but language
1562 code types may not be mixed in a single call to this function. This function
1563 supports a variable argument list that allows the caller to pass in a prioritized
1564 list of language codes to test against all the language codes in SupportedLanguages.
1566 If SupportedLanguages is NULL, then ASSERT().
1568 @param[in] SupportedLanguages A pointer to a Null-terminated ASCII string that
1569 contains a set of language codes in the format
1570 specified by Iso639Language.
1571 @param[in] Iso639Language If TRUE, then all language codes are assumed to be
1572 in ISO 639-2 format. If FALSE, then all language
1573 codes are assumed to be in RFC 4646 language format
1574 @param[in] ... A variable argument list that contains pointers to
1575 Null-terminated ASCII strings that contain one or more
1576 language codes in the format specified by Iso639Language.
1577 The first language code from each of these language
1578 code lists is used to determine if it is an exact or
1579 close match to any of the language codes in
1580 SupportedLanguages. Close matches only apply to RFC 4646
1581 language codes, and the matching algorithm from RFC 4647
1582 is used to determine if a close match is present. If
1583 an exact or close match is found, then the matching
1584 language code from SupportedLanguages is returned. If
1585 no matches are found, then the next variable argument
1586 parameter is evaluated. The variable argument list
1587 is terminated by a NULL.
1589 @retval NULL The best matching language could not be found in SupportedLanguages.
1590 @retval NULL There are not enough resources available to return the best matching
1592 @retval Other A pointer to a Null-terminated ASCII string that is the best matching
1593 language in SupportedLanguages.
1598 VariableGetBestLanguage (
1599 IN CONST CHAR8
*SupportedLanguages
,
1600 IN BOOLEAN Iso639Language
,
1606 UINTN CompareLength
;
1607 UINTN LanguageLength
;
1608 CONST CHAR8
*Supported
;
1611 if (SupportedLanguages
== NULL
) {
1615 VA_START (Args
, Iso639Language
);
1616 while ((Language
= VA_ARG (Args
, CHAR8
*)) != NULL
) {
1618 // Default to ISO 639-2 mode
1621 LanguageLength
= MIN (3, AsciiStrLen (Language
));
1624 // If in RFC 4646 mode, then determine the length of the first RFC 4646 language code in Language
1626 if (!Iso639Language
) {
1627 for (LanguageLength
= 0; Language
[LanguageLength
] != 0 && Language
[LanguageLength
] != ';'; LanguageLength
++);
1631 // Trim back the length of Language used until it is empty
1633 while (LanguageLength
> 0) {
1635 // Loop through all language codes in SupportedLanguages
1637 for (Supported
= SupportedLanguages
; *Supported
!= '\0'; Supported
+= CompareLength
) {
1639 // In RFC 4646 mode, then Loop through all language codes in SupportedLanguages
1641 if (!Iso639Language
) {
1643 // Skip ';' characters in Supported
1645 for (; *Supported
!= '\0' && *Supported
== ';'; Supported
++);
1647 // Determine the length of the next language code in Supported
1649 for (CompareLength
= 0; Supported
[CompareLength
] != 0 && Supported
[CompareLength
] != ';'; CompareLength
++);
1651 // If Language is longer than the Supported, then skip to the next language
1653 if (LanguageLength
> CompareLength
) {
1658 // See if the first LanguageLength characters in Supported match Language
1660 if (AsciiStrnCmp (Supported
, Language
, LanguageLength
) == 0) {
1663 Buffer
= Iso639Language
? mVariableModuleGlobal
->Lang
: mVariableModuleGlobal
->PlatformLang
;
1664 Buffer
[CompareLength
] = '\0';
1665 return CopyMem (Buffer
, Supported
, CompareLength
);
1669 if (Iso639Language
) {
1671 // If ISO 639 mode, then each language can only be tested once
1676 // If RFC 4646 mode, then trim Language from the right to the next '-' character
1678 for (LanguageLength
--; LanguageLength
> 0 && Language
[LanguageLength
] != '-'; LanguageLength
--);
1685 // No matches were found
1691 This function is to check if the remaining variable space is enough to set
1692 all Variables from argument list successfully. The purpose of the check
1693 is to keep the consistency of the Variables to be in variable storage.
1695 Note: Variables are assumed to be in same storage.
1696 The set sequence of Variables will be same with the sequence of VariableEntry from argument list,
1697 so follow the argument sequence to check the Variables.
1699 @param[in] Attributes Variable attributes for Variable entries.
1700 @param[in] Marker VA_LIST style variable argument list.
1701 The variable argument list with type VARIABLE_ENTRY_CONSISTENCY *.
1702 A NULL terminates the list. The VariableSize of
1703 VARIABLE_ENTRY_CONSISTENCY is the variable data size as input.
1704 It will be changed to variable total size as output.
1706 @retval TRUE Have enough variable space to set the Variables successfully.
1707 @retval FALSE No enough variable space to set the Variables successfully.
1712 CheckRemainingSpaceForConsistencyInternal (
1713 IN UINT32 Attributes
,
1719 VARIABLE_ENTRY_CONSISTENCY
*VariableEntry
;
1720 UINT64 MaximumVariableStorageSize
;
1721 UINT64 RemainingVariableStorageSize
;
1722 UINT64 MaximumVariableSize
;
1723 UINTN TotalNeededSize
;
1724 UINTN OriginalVarSize
;
1725 VARIABLE_STORE_HEADER
*VariableStoreHeader
;
1726 VARIABLE_POINTER_TRACK VariablePtrTrack
;
1727 VARIABLE_HEADER
*NextVariable
;
1732 // Non-Volatile related.
1734 VariableStoreHeader
= mNvVariableCache
;
1736 Status
= VariableServiceQueryVariableInfoInternal (
1738 &MaximumVariableStorageSize
,
1739 &RemainingVariableStorageSize
,
1740 &MaximumVariableSize
1742 ASSERT_EFI_ERROR (Status
);
1744 TotalNeededSize
= 0;
1745 VA_COPY (Args
, Marker
);
1746 VariableEntry
= VA_ARG (Args
, VARIABLE_ENTRY_CONSISTENCY
*);
1747 while (VariableEntry
!= NULL
) {
1749 // Calculate variable total size.
1751 VarNameSize
= StrSize (VariableEntry
->Name
);
1752 VarNameSize
+= GET_PAD_SIZE (VarNameSize
);
1753 VarDataSize
= VariableEntry
->VariableSize
;
1754 VarDataSize
+= GET_PAD_SIZE (VarDataSize
);
1755 VariableEntry
->VariableSize
= HEADER_ALIGN (GetVariableHeaderSize () + VarNameSize
+ VarDataSize
);
1757 TotalNeededSize
+= VariableEntry
->VariableSize
;
1758 VariableEntry
= VA_ARG (Args
, VARIABLE_ENTRY_CONSISTENCY
*);
1762 if (RemainingVariableStorageSize
>= TotalNeededSize
) {
1764 // Already have enough space.
1767 } else if (AtRuntime ()) {
1769 // At runtime, no reclaim.
1770 // The original variable space of Variables can't be reused.
1775 VA_COPY (Args
, Marker
);
1776 VariableEntry
= VA_ARG (Args
, VARIABLE_ENTRY_CONSISTENCY
*);
1777 while (VariableEntry
!= NULL
) {
1779 // Check if Variable[Index] has been present and get its size.
1781 OriginalVarSize
= 0;
1782 VariablePtrTrack
.StartPtr
= GetStartPointer (VariableStoreHeader
);
1783 VariablePtrTrack
.EndPtr
= GetEndPointer (VariableStoreHeader
);
1784 Status
= FindVariableEx (
1785 VariableEntry
->Name
,
1786 VariableEntry
->Guid
,
1790 if (!EFI_ERROR (Status
)) {
1792 // Get size of Variable[Index].
1794 NextVariable
= GetNextVariablePtr (VariablePtrTrack
.CurrPtr
);
1795 OriginalVarSize
= (UINTN
) NextVariable
- (UINTN
) VariablePtrTrack
.CurrPtr
;
1797 // Add the original size of Variable[Index] to remaining variable storage size.
1799 RemainingVariableStorageSize
+= OriginalVarSize
;
1801 if (VariableEntry
->VariableSize
> RemainingVariableStorageSize
) {
1803 // No enough space for Variable[Index].
1808 // Sub the (new) size of Variable[Index] from remaining variable storage size.
1810 RemainingVariableStorageSize
-= VariableEntry
->VariableSize
;
1811 VariableEntry
= VA_ARG (Args
, VARIABLE_ENTRY_CONSISTENCY
*);
1819 This function is to check if the remaining variable space is enough to set
1820 all Variables from argument list successfully. The purpose of the check
1821 is to keep the consistency of the Variables to be in variable storage.
1823 Note: Variables are assumed to be in same storage.
1824 The set sequence of Variables will be same with the sequence of VariableEntry from argument list,
1825 so follow the argument sequence to check the Variables.
1827 @param[in] Attributes Variable attributes for Variable entries.
1828 @param ... The variable argument list with type VARIABLE_ENTRY_CONSISTENCY *.
1829 A NULL terminates the list. The VariableSize of
1830 VARIABLE_ENTRY_CONSISTENCY is the variable data size as input.
1831 It will be changed to variable total size as output.
1833 @retval TRUE Have enough variable space to set the Variables successfully.
1834 @retval FALSE No enough variable space to set the Variables successfully.
1839 CheckRemainingSpaceForConsistency (
1840 IN UINT32 Attributes
,
1847 VA_START (Marker
, Attributes
);
1849 Return
= CheckRemainingSpaceForConsistencyInternal (Attributes
, Marker
);
1857 Hook the operations in PlatformLangCodes, LangCodes, PlatformLang and Lang.
1859 When setting Lang/LangCodes, simultaneously update PlatformLang/PlatformLangCodes.
1861 According to UEFI spec, PlatformLangCodes/LangCodes are only set once in firmware initialization,
1862 and are read-only. Therefore, in variable driver, only store the original value for other use.
1864 @param[in] VariableName Name of variable.
1866 @param[in] Data Variable data.
1868 @param[in] DataSize Size of data. 0 means delete.
1870 @retval EFI_SUCCESS The update operation is successful or ignored.
1871 @retval EFI_WRITE_PROTECTED Update PlatformLangCodes/LangCodes at runtime.
1872 @retval EFI_OUT_OF_RESOURCES No enough variable space to do the update operation.
1873 @retval Others Other errors happened during the update operation.
1877 AutoUpdateLangVariable (
1878 IN CHAR16
*VariableName
,
1884 CHAR8
*BestPlatformLang
;
1888 VARIABLE_POINTER_TRACK Variable
;
1889 BOOLEAN SetLanguageCodes
;
1890 VARIABLE_ENTRY_CONSISTENCY VariableEntry
[2];
1893 // Don't do updates for delete operation
1895 if (DataSize
== 0) {
1899 SetLanguageCodes
= FALSE
;
1901 if (StrCmp (VariableName
, EFI_PLATFORM_LANG_CODES_VARIABLE_NAME
) == 0) {
1903 // PlatformLangCodes is a volatile variable, so it can not be updated at runtime.
1906 return EFI_WRITE_PROTECTED
;
1909 SetLanguageCodes
= TRUE
;
1912 // According to UEFI spec, PlatformLangCodes is only set once in firmware initialization, and is read-only
1913 // Therefore, in variable driver, only store the original value for other use.
1915 if (mVariableModuleGlobal
->PlatformLangCodes
!= NULL
) {
1916 FreePool (mVariableModuleGlobal
->PlatformLangCodes
);
1918 mVariableModuleGlobal
->PlatformLangCodes
= AllocateRuntimeCopyPool (DataSize
, Data
);
1919 ASSERT (mVariableModuleGlobal
->PlatformLangCodes
!= NULL
);
1922 // PlatformLang holds a single language from PlatformLangCodes,
1923 // so the size of PlatformLangCodes is enough for the PlatformLang.
1925 if (mVariableModuleGlobal
->PlatformLang
!= NULL
) {
1926 FreePool (mVariableModuleGlobal
->PlatformLang
);
1928 mVariableModuleGlobal
->PlatformLang
= AllocateRuntimePool (DataSize
);
1929 ASSERT (mVariableModuleGlobal
->PlatformLang
!= NULL
);
1931 } else if (StrCmp (VariableName
, EFI_LANG_CODES_VARIABLE_NAME
) == 0) {
1933 // LangCodes is a volatile variable, so it can not be updated at runtime.
1936 return EFI_WRITE_PROTECTED
;
1939 SetLanguageCodes
= TRUE
;
1942 // According to UEFI spec, LangCodes is only set once in firmware initialization, and is read-only
1943 // Therefore, in variable driver, only store the original value for other use.
1945 if (mVariableModuleGlobal
->LangCodes
!= NULL
) {
1946 FreePool (mVariableModuleGlobal
->LangCodes
);
1948 mVariableModuleGlobal
->LangCodes
= AllocateRuntimeCopyPool (DataSize
, Data
);
1949 ASSERT (mVariableModuleGlobal
->LangCodes
!= NULL
);
1952 if (SetLanguageCodes
1953 && (mVariableModuleGlobal
->PlatformLangCodes
!= NULL
)
1954 && (mVariableModuleGlobal
->LangCodes
!= NULL
)) {
1956 // Update Lang if PlatformLang is already set
1957 // Update PlatformLang if Lang is already set
1959 Status
= FindVariable (EFI_PLATFORM_LANG_VARIABLE_NAME
, &gEfiGlobalVariableGuid
, &Variable
, &mVariableModuleGlobal
->VariableGlobal
, FALSE
);
1960 if (!EFI_ERROR (Status
)) {
1964 VariableName
= EFI_PLATFORM_LANG_VARIABLE_NAME
;
1965 Data
= GetVariableDataPtr (Variable
.CurrPtr
);
1966 DataSize
= DataSizeOfVariable (Variable
.CurrPtr
);
1968 Status
= FindVariable (EFI_LANG_VARIABLE_NAME
, &gEfiGlobalVariableGuid
, &Variable
, &mVariableModuleGlobal
->VariableGlobal
, FALSE
);
1969 if (!EFI_ERROR (Status
)) {
1971 // Update PlatformLang
1973 VariableName
= EFI_LANG_VARIABLE_NAME
;
1974 Data
= GetVariableDataPtr (Variable
.CurrPtr
);
1975 DataSize
= DataSizeOfVariable (Variable
.CurrPtr
);
1978 // Neither PlatformLang nor Lang is set, directly return
1985 Status
= EFI_SUCCESS
;
1988 // According to UEFI spec, "Lang" and "PlatformLang" is NV|BS|RT attributions.
1990 Attributes
= EFI_VARIABLE_NON_VOLATILE
| EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_RUNTIME_ACCESS
;
1992 if (StrCmp (VariableName
, EFI_PLATFORM_LANG_VARIABLE_NAME
) == 0) {
1994 // Update Lang when PlatformLangCodes/LangCodes were set.
1996 if ((mVariableModuleGlobal
->PlatformLangCodes
!= NULL
) && (mVariableModuleGlobal
->LangCodes
!= NULL
)) {
1998 // When setting PlatformLang, firstly get most matched language string from supported language codes.
2000 BestPlatformLang
= VariableGetBestLanguage (mVariableModuleGlobal
->PlatformLangCodes
, FALSE
, Data
, NULL
);
2001 if (BestPlatformLang
!= NULL
) {
2003 // Get the corresponding index in language codes.
2005 Index
= GetIndexFromSupportedLangCodes (mVariableModuleGlobal
->PlatformLangCodes
, BestPlatformLang
, FALSE
);
2008 // Get the corresponding ISO639 language tag according to RFC4646 language tag.
2010 BestLang
= GetLangFromSupportedLangCodes (mVariableModuleGlobal
->LangCodes
, Index
, TRUE
);
2013 // Check the variable space for both Lang and PlatformLang variable.
2015 VariableEntry
[0].VariableSize
= ISO_639_2_ENTRY_SIZE
+ 1;
2016 VariableEntry
[0].Guid
= &gEfiGlobalVariableGuid
;
2017 VariableEntry
[0].Name
= EFI_LANG_VARIABLE_NAME
;
2019 VariableEntry
[1].VariableSize
= AsciiStrSize (BestPlatformLang
);
2020 VariableEntry
[1].Guid
= &gEfiGlobalVariableGuid
;
2021 VariableEntry
[1].Name
= EFI_PLATFORM_LANG_VARIABLE_NAME
;
2022 if (!CheckRemainingSpaceForConsistency (VARIABLE_ATTRIBUTE_NV_BS_RT
, &VariableEntry
[0], &VariableEntry
[1], NULL
)) {
2024 // No enough variable space to set both Lang and PlatformLang successfully.
2026 Status
= EFI_OUT_OF_RESOURCES
;
2029 // Successfully convert PlatformLang to Lang, and set the BestLang value into Lang variable simultaneously.
2031 FindVariable (EFI_LANG_VARIABLE_NAME
, &gEfiGlobalVariableGuid
, &Variable
, &mVariableModuleGlobal
->VariableGlobal
, FALSE
);
2033 Status
= UpdateVariable (EFI_LANG_VARIABLE_NAME
, &gEfiGlobalVariableGuid
, BestLang
,
2034 ISO_639_2_ENTRY_SIZE
+ 1, Attributes
, 0, 0, &Variable
, NULL
);
2037 DEBUG ((EFI_D_INFO
, "Variable Driver Auto Update PlatformLang, PlatformLang:%a, Lang:%a Status: %r\n", BestPlatformLang
, BestLang
, Status
));
2041 } else if (StrCmp (VariableName
, EFI_LANG_VARIABLE_NAME
) == 0) {
2043 // Update PlatformLang when PlatformLangCodes/LangCodes were set.
2045 if ((mVariableModuleGlobal
->PlatformLangCodes
!= NULL
) && (mVariableModuleGlobal
->LangCodes
!= NULL
)) {
2047 // When setting Lang, firstly get most matched language string from supported language codes.
2049 BestLang
= VariableGetBestLanguage (mVariableModuleGlobal
->LangCodes
, TRUE
, Data
, NULL
);
2050 if (BestLang
!= NULL
) {
2052 // Get the corresponding index in language codes.
2054 Index
= GetIndexFromSupportedLangCodes (mVariableModuleGlobal
->LangCodes
, BestLang
, TRUE
);
2057 // Get the corresponding RFC4646 language tag according to ISO639 language tag.
2059 BestPlatformLang
= GetLangFromSupportedLangCodes (mVariableModuleGlobal
->PlatformLangCodes
, Index
, FALSE
);
2062 // Check the variable space for both PlatformLang and Lang variable.
2064 VariableEntry
[0].VariableSize
= AsciiStrSize (BestPlatformLang
);
2065 VariableEntry
[0].Guid
= &gEfiGlobalVariableGuid
;
2066 VariableEntry
[0].Name
= EFI_PLATFORM_LANG_VARIABLE_NAME
;
2068 VariableEntry
[1].VariableSize
= ISO_639_2_ENTRY_SIZE
+ 1;
2069 VariableEntry
[1].Guid
= &gEfiGlobalVariableGuid
;
2070 VariableEntry
[1].Name
= EFI_LANG_VARIABLE_NAME
;
2071 if (!CheckRemainingSpaceForConsistency (VARIABLE_ATTRIBUTE_NV_BS_RT
, &VariableEntry
[0], &VariableEntry
[1], NULL
)) {
2073 // No enough variable space to set both PlatformLang and Lang successfully.
2075 Status
= EFI_OUT_OF_RESOURCES
;
2078 // Successfully convert Lang to PlatformLang, and set the BestPlatformLang value into PlatformLang variable simultaneously.
2080 FindVariable (EFI_PLATFORM_LANG_VARIABLE_NAME
, &gEfiGlobalVariableGuid
, &Variable
, &mVariableModuleGlobal
->VariableGlobal
, FALSE
);
2082 Status
= UpdateVariable (EFI_PLATFORM_LANG_VARIABLE_NAME
, &gEfiGlobalVariableGuid
, BestPlatformLang
,
2083 AsciiStrSize (BestPlatformLang
), Attributes
, 0, 0, &Variable
, NULL
);
2086 DEBUG ((EFI_D_INFO
, "Variable Driver Auto Update Lang, Lang:%a, PlatformLang:%a Status: %r\n", BestLang
, BestPlatformLang
, Status
));
2091 if (SetLanguageCodes
) {
2093 // Continue to set PlatformLangCodes or LangCodes.
2102 Compare two EFI_TIME data.
2105 @param FirstTime A pointer to the first EFI_TIME data.
2106 @param SecondTime A pointer to the second EFI_TIME data.
2108 @retval TRUE The FirstTime is not later than the SecondTime.
2109 @retval FALSE The FirstTime is later than the SecondTime.
2113 VariableCompareTimeStampInternal (
2114 IN EFI_TIME
*FirstTime
,
2115 IN EFI_TIME
*SecondTime
2118 if (FirstTime
->Year
!= SecondTime
->Year
) {
2119 return (BOOLEAN
) (FirstTime
->Year
< SecondTime
->Year
);
2120 } else if (FirstTime
->Month
!= SecondTime
->Month
) {
2121 return (BOOLEAN
) (FirstTime
->Month
< SecondTime
->Month
);
2122 } else if (FirstTime
->Day
!= SecondTime
->Day
) {
2123 return (BOOLEAN
) (FirstTime
->Day
< SecondTime
->Day
);
2124 } else if (FirstTime
->Hour
!= SecondTime
->Hour
) {
2125 return (BOOLEAN
) (FirstTime
->Hour
< SecondTime
->Hour
);
2126 } else if (FirstTime
->Minute
!= SecondTime
->Minute
) {
2127 return (BOOLEAN
) (FirstTime
->Minute
< SecondTime
->Minute
);
2130 return (BOOLEAN
) (FirstTime
->Second
<= SecondTime
->Second
);
2134 Update the variable region with Variable information. If EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS is set,
2135 index of associated public key is needed.
2137 @param[in] VariableName Name of variable.
2138 @param[in] VendorGuid Guid of variable.
2139 @param[in] Data Variable data.
2140 @param[in] DataSize Size of data. 0 means delete.
2141 @param[in] Attributes Attributes of the variable.
2142 @param[in] KeyIndex Index of associated public key.
2143 @param[in] MonotonicCount Value of associated monotonic count.
2144 @param[in, out] CacheVariable The variable information which is used to keep track of variable usage.
2145 @param[in] TimeStamp Value of associated TimeStamp.
2147 @retval EFI_SUCCESS The update operation is success.
2148 @retval EFI_OUT_OF_RESOURCES Variable region is full, can not write other data into this region.
2153 IN CHAR16
*VariableName
,
2154 IN EFI_GUID
*VendorGuid
,
2157 IN UINT32 Attributes OPTIONAL
,
2158 IN UINT32 KeyIndex OPTIONAL
,
2159 IN UINT64 MonotonicCount OPTIONAL
,
2160 IN OUT VARIABLE_POINTER_TRACK
*CacheVariable
,
2161 IN EFI_TIME
*TimeStamp OPTIONAL
2165 VARIABLE_HEADER
*NextVariable
;
2168 UINTN VarNameOffset
;
2169 UINTN VarDataOffset
;
2173 EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*Fvb
;
2175 VARIABLE_POINTER_TRACK
*Variable
;
2176 VARIABLE_POINTER_TRACK NvVariable
;
2177 VARIABLE_STORE_HEADER
*VariableStoreHeader
;
2179 UINT8
*BufferForMerge
;
2180 UINTN MergedBufSize
;
2183 BOOLEAN IsCommonVariable
;
2184 BOOLEAN IsCommonUserVariable
;
2185 AUTHENTICATED_VARIABLE_HEADER
*AuthVariable
;
2187 if (mVariableModuleGlobal
->FvbInstance
== NULL
) {
2189 // The FVB protocol is not ready, so the EFI_VARIABLE_WRITE_ARCH_PROTOCOL is not installed.
2191 if ((Attributes
& EFI_VARIABLE_NON_VOLATILE
) != 0) {
2193 // Trying to update NV variable prior to the installation of EFI_VARIABLE_WRITE_ARCH_PROTOCOL
2195 DEBUG ((EFI_D_ERROR
, "Update NV variable before EFI_VARIABLE_WRITE_ARCH_PROTOCOL ready - %r\n", EFI_NOT_AVAILABLE_YET
));
2196 return EFI_NOT_AVAILABLE_YET
;
2197 } else if ((Attributes
& VARIABLE_ATTRIBUTE_AT_AW
) != 0) {
2199 // Trying to update volatile authenticated variable prior to the installation of EFI_VARIABLE_WRITE_ARCH_PROTOCOL
2200 // The authenticated variable perhaps is not initialized, just return here.
2202 DEBUG ((EFI_D_ERROR
, "Update AUTH variable before EFI_VARIABLE_WRITE_ARCH_PROTOCOL ready - %r\n", EFI_NOT_AVAILABLE_YET
));
2203 return EFI_NOT_AVAILABLE_YET
;
2208 // Check if CacheVariable points to the variable in variable HOB.
2209 // If yes, let CacheVariable points to the variable in NV variable cache.
2211 if ((CacheVariable
->CurrPtr
!= NULL
) &&
2212 (mVariableModuleGlobal
->VariableGlobal
.HobVariableBase
!= 0) &&
2213 (CacheVariable
->StartPtr
== GetStartPointer ((VARIABLE_STORE_HEADER
*) (UINTN
) mVariableModuleGlobal
->VariableGlobal
.HobVariableBase
))
2215 CacheVariable
->StartPtr
= GetStartPointer (mNvVariableCache
);
2216 CacheVariable
->EndPtr
= GetEndPointer (mNvVariableCache
);
2217 CacheVariable
->Volatile
= FALSE
;
2218 Status
= FindVariableEx (VariableName
, VendorGuid
, FALSE
, CacheVariable
);
2219 if (CacheVariable
->CurrPtr
== NULL
|| EFI_ERROR (Status
)) {
2221 // There is no matched variable in NV variable cache.
2223 if ((((Attributes
& EFI_VARIABLE_APPEND_WRITE
) == 0) && (DataSize
== 0)) || (Attributes
== 0)) {
2225 // It is to delete variable,
2226 // go to delete this variable in variable HOB and
2227 // try to flush other variables from HOB to flash.
2229 UpdateVariableInfo (VariableName
, VendorGuid
, FALSE
, FALSE
, FALSE
, TRUE
, FALSE
);
2230 FlushHobVariableToFlash (VariableName
, VendorGuid
);
2236 if ((CacheVariable
->CurrPtr
== NULL
) || CacheVariable
->Volatile
) {
2237 Variable
= CacheVariable
;
2240 // Update/Delete existing NV variable.
2241 // CacheVariable points to the variable in the memory copy of Flash area
2242 // Now let Variable points to the same variable in Flash area.
2244 VariableStoreHeader
= (VARIABLE_STORE_HEADER
*) ((UINTN
) mVariableModuleGlobal
->VariableGlobal
.NonVolatileVariableBase
);
2245 Variable
= &NvVariable
;
2246 Variable
->StartPtr
= GetStartPointer (VariableStoreHeader
);
2247 Variable
->EndPtr
= (VARIABLE_HEADER
*)((UINTN
)Variable
->StartPtr
+ ((UINTN
)CacheVariable
->EndPtr
- (UINTN
)CacheVariable
->StartPtr
));
2249 Variable
->CurrPtr
= (VARIABLE_HEADER
*)((UINTN
)Variable
->StartPtr
+ ((UINTN
)CacheVariable
->CurrPtr
- (UINTN
)CacheVariable
->StartPtr
));
2250 if (CacheVariable
->InDeletedTransitionPtr
!= NULL
) {
2251 Variable
->InDeletedTransitionPtr
= (VARIABLE_HEADER
*)((UINTN
)Variable
->StartPtr
+ ((UINTN
)CacheVariable
->InDeletedTransitionPtr
- (UINTN
)CacheVariable
->StartPtr
));
2253 Variable
->InDeletedTransitionPtr
= NULL
;
2255 Variable
->Volatile
= FALSE
;
2258 Fvb
= mVariableModuleGlobal
->FvbInstance
;
2261 // Tricky part: Use scratch data area at the end of volatile variable store
2262 // as a temporary storage.
2264 NextVariable
= GetEndPointer ((VARIABLE_STORE_HEADER
*) ((UINTN
) mVariableModuleGlobal
->VariableGlobal
.VolatileVariableBase
));
2265 ScratchSize
= mVariableModuleGlobal
->ScratchBufferSize
;
2266 SetMem (NextVariable
, ScratchSize
, 0xff);
2269 if (Variable
->CurrPtr
!= NULL
) {
2271 // Update/Delete existing variable.
2275 // If AtRuntime and the variable is Volatile and Runtime Access,
2276 // the volatile is ReadOnly, and SetVariable should be aborted and
2277 // return EFI_WRITE_PROTECTED.
2279 if (Variable
->Volatile
) {
2280 Status
= EFI_WRITE_PROTECTED
;
2284 // Only variable that have NV attributes can be updated/deleted in Runtime.
2286 if ((CacheVariable
->CurrPtr
->Attributes
& EFI_VARIABLE_NON_VOLATILE
) == 0) {
2287 Status
= EFI_INVALID_PARAMETER
;
2292 // Only variable that have RT attributes can be updated/deleted in Runtime.
2294 if ((CacheVariable
->CurrPtr
->Attributes
& EFI_VARIABLE_RUNTIME_ACCESS
) == 0) {
2295 Status
= EFI_INVALID_PARAMETER
;
2301 // Setting a data variable with no access, or zero DataSize attributes
2302 // causes it to be deleted.
2303 // When the EFI_VARIABLE_APPEND_WRITE attribute is set, DataSize of zero will
2304 // not delete the variable.
2306 if ((((Attributes
& EFI_VARIABLE_APPEND_WRITE
) == 0) && (DataSize
== 0))|| ((Attributes
& (EFI_VARIABLE_RUNTIME_ACCESS
| EFI_VARIABLE_BOOTSERVICE_ACCESS
)) == 0)) {
2307 if (Variable
->InDeletedTransitionPtr
!= NULL
) {
2309 // Both ADDED and IN_DELETED_TRANSITION variable are present,
2310 // set IN_DELETED_TRANSITION one to DELETED state first.
2312 ASSERT (CacheVariable
->InDeletedTransitionPtr
!= NULL
);
2313 State
= CacheVariable
->InDeletedTransitionPtr
->State
;
2314 State
&= VAR_DELETED
;
2315 Status
= UpdateVariableStore (
2316 &mVariableModuleGlobal
->VariableGlobal
,
2320 (UINTN
) &Variable
->InDeletedTransitionPtr
->State
,
2324 if (!EFI_ERROR (Status
)) {
2325 if (!Variable
->Volatile
) {
2326 CacheVariable
->InDeletedTransitionPtr
->State
= State
;
2333 State
= CacheVariable
->CurrPtr
->State
;
2334 State
&= VAR_DELETED
;
2336 Status
= UpdateVariableStore (
2337 &mVariableModuleGlobal
->VariableGlobal
,
2341 (UINTN
) &Variable
->CurrPtr
->State
,
2345 if (!EFI_ERROR (Status
)) {
2346 UpdateVariableInfo (VariableName
, VendorGuid
, Variable
->Volatile
, FALSE
, FALSE
, TRUE
, FALSE
);
2347 if (!Variable
->Volatile
) {
2348 CacheVariable
->CurrPtr
->State
= State
;
2349 FlushHobVariableToFlash (VariableName
, VendorGuid
);
2355 // If the variable is marked valid, and the same data has been passed in,
2356 // then return to the caller immediately.
2358 if (DataSizeOfVariable (CacheVariable
->CurrPtr
) == DataSize
&&
2359 (CompareMem (Data
, GetVariableDataPtr (CacheVariable
->CurrPtr
), DataSize
) == 0) &&
2360 ((Attributes
& EFI_VARIABLE_APPEND_WRITE
) == 0) &&
2361 (TimeStamp
== NULL
)) {
2363 // Variable content unchanged and no need to update timestamp, just return.
2365 UpdateVariableInfo (VariableName
, VendorGuid
, Variable
->Volatile
, FALSE
, TRUE
, FALSE
, FALSE
);
2366 Status
= EFI_SUCCESS
;
2368 } else if ((CacheVariable
->CurrPtr
->State
== VAR_ADDED
) ||
2369 (CacheVariable
->CurrPtr
->State
== (VAR_ADDED
& VAR_IN_DELETED_TRANSITION
))) {
2372 // EFI_VARIABLE_APPEND_WRITE attribute only effects for existing variable.
2374 if ((Attributes
& EFI_VARIABLE_APPEND_WRITE
) != 0) {
2376 // NOTE: From 0 to DataOffset of NextVariable is reserved for Variable Header and Name.
2377 // From DataOffset of NextVariable is to save the existing variable data.
2379 DataOffset
= GetVariableDataOffset (CacheVariable
->CurrPtr
);
2380 BufferForMerge
= (UINT8
*) ((UINTN
) NextVariable
+ DataOffset
);
2381 CopyMem (BufferForMerge
, (UINT8
*) ((UINTN
) CacheVariable
->CurrPtr
+ DataOffset
), DataSizeOfVariable (CacheVariable
->CurrPtr
));
2384 // Set Max Common/Auth Variable Data Size as default MaxDataSize.
2386 if ((Attributes
& VARIABLE_ATTRIBUTE_AT_AW
) != 0) {
2387 MaxDataSize
= mVariableModuleGlobal
->MaxAuthVariableSize
- DataOffset
;
2389 MaxDataSize
= mVariableModuleGlobal
->MaxVariableSize
- DataOffset
;
2393 // Append the new data to the end of existing data.
2394 // Max Harware error record variable data size is different from common/auth variable.
2396 if ((Attributes
& EFI_VARIABLE_HARDWARE_ERROR_RECORD
) == EFI_VARIABLE_HARDWARE_ERROR_RECORD
) {
2397 MaxDataSize
= PcdGet32 (PcdMaxHardwareErrorVariableSize
) - DataOffset
;
2400 if (DataSizeOfVariable (CacheVariable
->CurrPtr
) + DataSize
> MaxDataSize
) {
2402 // Existing data size + new data size exceed maximum variable size limitation.
2404 Status
= EFI_INVALID_PARAMETER
;
2407 CopyMem ((UINT8
*) ((UINTN
) BufferForMerge
+ DataSizeOfVariable (CacheVariable
->CurrPtr
)), Data
, DataSize
);
2408 MergedBufSize
= DataSizeOfVariable (CacheVariable
->CurrPtr
) + DataSize
;
2411 // BufferForMerge(from DataOffset of NextVariable) has included the merged existing and new data.
2413 Data
= BufferForMerge
;
2414 DataSize
= MergedBufSize
;
2419 // Mark the old variable as in delete transition.
2421 State
= CacheVariable
->CurrPtr
->State
;
2422 State
&= VAR_IN_DELETED_TRANSITION
;
2424 Status
= UpdateVariableStore (
2425 &mVariableModuleGlobal
->VariableGlobal
,
2429 (UINTN
) &Variable
->CurrPtr
->State
,
2433 if (EFI_ERROR (Status
)) {
2436 if (!Variable
->Volatile
) {
2437 CacheVariable
->CurrPtr
->State
= State
;
2442 // Not found existing variable. Create a new variable.
2445 if ((DataSize
== 0) && ((Attributes
& EFI_VARIABLE_APPEND_WRITE
) != 0)) {
2446 Status
= EFI_SUCCESS
;
2451 // Make sure we are trying to create a new variable.
2452 // Setting a data variable with zero DataSize or no access attributes means to delete it.
2454 if (DataSize
== 0 || (Attributes
& (EFI_VARIABLE_RUNTIME_ACCESS
| EFI_VARIABLE_BOOTSERVICE_ACCESS
)) == 0) {
2455 Status
= EFI_NOT_FOUND
;
2460 // Only variable have NV|RT attribute can be created in Runtime.
2463 (((Attributes
& EFI_VARIABLE_RUNTIME_ACCESS
) == 0) || ((Attributes
& EFI_VARIABLE_NON_VOLATILE
) == 0))) {
2464 Status
= EFI_INVALID_PARAMETER
;
2470 // Function part - create a new variable and copy the data.
2471 // Both update a variable and create a variable will come here.
2473 NextVariable
->StartId
= VARIABLE_DATA
;
2475 // NextVariable->State = VAR_ADDED;
2477 NextVariable
->Reserved
= 0;
2478 if (mVariableModuleGlobal
->VariableGlobal
.AuthFormat
) {
2479 AuthVariable
= (AUTHENTICATED_VARIABLE_HEADER
*) NextVariable
;
2480 AuthVariable
->PubKeyIndex
= KeyIndex
;
2481 AuthVariable
->MonotonicCount
= MonotonicCount
;
2482 ZeroMem (&AuthVariable
->TimeStamp
, sizeof (EFI_TIME
));
2484 if (((Attributes
& EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS
) != 0) &&
2485 (TimeStamp
!= NULL
)) {
2486 if ((Attributes
& EFI_VARIABLE_APPEND_WRITE
) == 0) {
2487 CopyMem (&AuthVariable
->TimeStamp
, TimeStamp
, sizeof (EFI_TIME
));
2490 // In the case when the EFI_VARIABLE_APPEND_WRITE attribute is set, only
2491 // when the new TimeStamp value is later than the current timestamp associated
2492 // with the variable, we need associate the new timestamp with the updated value.
2494 if (Variable
->CurrPtr
!= NULL
) {
2495 if (VariableCompareTimeStampInternal (&(((AUTHENTICATED_VARIABLE_HEADER
*) CacheVariable
->CurrPtr
)->TimeStamp
), TimeStamp
)) {
2496 CopyMem (&AuthVariable
->TimeStamp
, TimeStamp
, sizeof (EFI_TIME
));
2504 // The EFI_VARIABLE_APPEND_WRITE attribute will never be set in the returned
2505 // Attributes bitmask parameter of a GetVariable() call.
2507 NextVariable
->Attributes
= Attributes
& (~EFI_VARIABLE_APPEND_WRITE
);
2509 VarNameOffset
= GetVariableHeaderSize ();
2510 VarNameSize
= StrSize (VariableName
);
2512 (UINT8
*) ((UINTN
) NextVariable
+ VarNameOffset
),
2516 VarDataOffset
= VarNameOffset
+ VarNameSize
+ GET_PAD_SIZE (VarNameSize
);
2519 // If DataReady is TRUE, it means the variable data has been saved into
2520 // NextVariable during EFI_VARIABLE_APPEND_WRITE operation preparation.
2524 (UINT8
*) ((UINTN
) NextVariable
+ VarDataOffset
),
2530 CopyMem (GetVendorGuidPtr (NextVariable
), VendorGuid
, sizeof (EFI_GUID
));
2532 // There will be pad bytes after Data, the NextVariable->NameSize and
2533 // NextVariable->DataSize should not include pad size so that variable
2534 // service can get actual size in GetVariable.
2536 SetNameSizeOfVariable (NextVariable
, VarNameSize
);
2537 SetDataSizeOfVariable (NextVariable
, DataSize
);
2540 // The actual size of the variable that stores in storage should
2541 // include pad size.
2543 VarSize
= VarDataOffset
+ DataSize
+ GET_PAD_SIZE (DataSize
);
2544 if ((Attributes
& EFI_VARIABLE_NON_VOLATILE
) != 0) {
2546 // Create a nonvolatile variable.
2550 IsCommonVariable
= FALSE
;
2551 IsCommonUserVariable
= FALSE
;
2552 if ((Attributes
& EFI_VARIABLE_HARDWARE_ERROR_RECORD
) == 0) {
2553 IsCommonVariable
= TRUE
;
2554 IsCommonUserVariable
= IsUserVariable (NextVariable
);
2556 if ((((Attributes
& EFI_VARIABLE_HARDWARE_ERROR_RECORD
) != 0)
2557 && ((VarSize
+ mVariableModuleGlobal
->HwErrVariableTotalSize
) > PcdGet32 (PcdHwErrStorageSize
)))
2558 || (IsCommonVariable
&& ((VarSize
+ mVariableModuleGlobal
->CommonVariableTotalSize
) > mVariableModuleGlobal
->CommonVariableSpace
))
2559 || (IsCommonVariable
&& AtRuntime () && ((VarSize
+ mVariableModuleGlobal
->CommonVariableTotalSize
) > mVariableModuleGlobal
->CommonRuntimeVariableSpace
))
2560 || (IsCommonUserVariable
&& ((VarSize
+ mVariableModuleGlobal
->CommonUserVariableTotalSize
) > mVariableModuleGlobal
->CommonMaxUserVariableSpace
))) {
2562 if (IsCommonUserVariable
&& ((VarSize
+ mVariableModuleGlobal
->CommonUserVariableTotalSize
) > mVariableModuleGlobal
->CommonMaxUserVariableSpace
)) {
2563 RecordVarErrorFlag (VAR_ERROR_FLAG_USER_ERROR
, VariableName
, VendorGuid
, Attributes
, VarSize
);
2565 if (IsCommonVariable
&& ((VarSize
+ mVariableModuleGlobal
->CommonVariableTotalSize
) > mVariableModuleGlobal
->CommonRuntimeVariableSpace
)) {
2566 RecordVarErrorFlag (VAR_ERROR_FLAG_SYSTEM_ERROR
, VariableName
, VendorGuid
, Attributes
, VarSize
);
2568 Status
= EFI_OUT_OF_RESOURCES
;
2572 // Perform garbage collection & reclaim operation, and integrate the new variable at the same time.
2575 mVariableModuleGlobal
->VariableGlobal
.NonVolatileVariableBase
,
2576 &mVariableModuleGlobal
->NonVolatileLastVariableOffset
,
2580 HEADER_ALIGN (VarSize
)
2582 if (!EFI_ERROR (Status
)) {
2584 // The new variable has been integrated successfully during reclaiming.
2586 if (Variable
->CurrPtr
!= NULL
) {
2587 CacheVariable
->CurrPtr
= (VARIABLE_HEADER
*)((UINTN
) CacheVariable
->StartPtr
+ ((UINTN
) Variable
->CurrPtr
- (UINTN
) Variable
->StartPtr
));
2588 CacheVariable
->InDeletedTransitionPtr
= NULL
;
2590 UpdateVariableInfo (VariableName
, VendorGuid
, FALSE
, FALSE
, TRUE
, FALSE
, FALSE
);
2591 FlushHobVariableToFlash (VariableName
, VendorGuid
);
2593 if (IsCommonUserVariable
&& ((VarSize
+ mVariableModuleGlobal
->CommonUserVariableTotalSize
) > mVariableModuleGlobal
->CommonMaxUserVariableSpace
)) {
2594 RecordVarErrorFlag (VAR_ERROR_FLAG_USER_ERROR
, VariableName
, VendorGuid
, Attributes
, VarSize
);
2596 if (IsCommonVariable
&& ((VarSize
+ mVariableModuleGlobal
->CommonVariableTotalSize
) > mVariableModuleGlobal
->CommonVariableSpace
)) {
2597 RecordVarErrorFlag (VAR_ERROR_FLAG_SYSTEM_ERROR
, VariableName
, VendorGuid
, Attributes
, VarSize
);
2604 // 1. Write variable header
2605 // 2. Set variable state to header valid
2606 // 3. Write variable data
2607 // 4. Set variable state to valid
2612 CacheOffset
= mVariableModuleGlobal
->NonVolatileLastVariableOffset
;
2613 Status
= UpdateVariableStore (
2614 &mVariableModuleGlobal
->VariableGlobal
,
2618 mVariableModuleGlobal
->NonVolatileLastVariableOffset
,
2619 (UINT32
) GetVariableHeaderSize (),
2620 (UINT8
*) NextVariable
2623 if (EFI_ERROR (Status
)) {
2630 NextVariable
->State
= VAR_HEADER_VALID_ONLY
;
2631 Status
= UpdateVariableStore (
2632 &mVariableModuleGlobal
->VariableGlobal
,
2636 mVariableModuleGlobal
->NonVolatileLastVariableOffset
+ OFFSET_OF (VARIABLE_HEADER
, State
),
2638 &NextVariable
->State
2641 if (EFI_ERROR (Status
)) {
2647 Status
= UpdateVariableStore (
2648 &mVariableModuleGlobal
->VariableGlobal
,
2652 mVariableModuleGlobal
->NonVolatileLastVariableOffset
+ GetVariableHeaderSize (),
2653 (UINT32
) (VarSize
- GetVariableHeaderSize ()),
2654 (UINT8
*) NextVariable
+ GetVariableHeaderSize ()
2657 if (EFI_ERROR (Status
)) {
2663 NextVariable
->State
= VAR_ADDED
;
2664 Status
= UpdateVariableStore (
2665 &mVariableModuleGlobal
->VariableGlobal
,
2669 mVariableModuleGlobal
->NonVolatileLastVariableOffset
+ OFFSET_OF (VARIABLE_HEADER
, State
),
2671 &NextVariable
->State
2674 if (EFI_ERROR (Status
)) {
2678 mVariableModuleGlobal
->NonVolatileLastVariableOffset
+= HEADER_ALIGN (VarSize
);
2680 if ((Attributes
& EFI_VARIABLE_HARDWARE_ERROR_RECORD
) != 0) {
2681 mVariableModuleGlobal
->HwErrVariableTotalSize
+= HEADER_ALIGN (VarSize
);
2683 mVariableModuleGlobal
->CommonVariableTotalSize
+= HEADER_ALIGN (VarSize
);
2684 if (IsCommonUserVariable
) {
2685 mVariableModuleGlobal
->CommonUserVariableTotalSize
+= HEADER_ALIGN (VarSize
);
2689 // update the memory copy of Flash region.
2691 CopyMem ((UINT8
*)mNvVariableCache
+ CacheOffset
, (UINT8
*)NextVariable
, VarSize
);
2694 // Create a volatile variable.
2698 if ((UINT32
) (VarSize
+ mVariableModuleGlobal
->VolatileLastVariableOffset
) >
2699 ((VARIABLE_STORE_HEADER
*) ((UINTN
) (mVariableModuleGlobal
->VariableGlobal
.VolatileVariableBase
)))->Size
) {
2701 // Perform garbage collection & reclaim operation, and integrate the new variable at the same time.
2704 mVariableModuleGlobal
->VariableGlobal
.VolatileVariableBase
,
2705 &mVariableModuleGlobal
->VolatileLastVariableOffset
,
2709 HEADER_ALIGN (VarSize
)
2711 if (!EFI_ERROR (Status
)) {
2713 // The new variable has been integrated successfully during reclaiming.
2715 if (Variable
->CurrPtr
!= NULL
) {
2716 CacheVariable
->CurrPtr
= (VARIABLE_HEADER
*)((UINTN
) CacheVariable
->StartPtr
+ ((UINTN
) Variable
->CurrPtr
- (UINTN
) Variable
->StartPtr
));
2717 CacheVariable
->InDeletedTransitionPtr
= NULL
;
2719 UpdateVariableInfo (VariableName
, VendorGuid
, TRUE
, FALSE
, TRUE
, FALSE
, FALSE
);
2724 NextVariable
->State
= VAR_ADDED
;
2725 Status
= UpdateVariableStore (
2726 &mVariableModuleGlobal
->VariableGlobal
,
2730 mVariableModuleGlobal
->VolatileLastVariableOffset
,
2732 (UINT8
*) NextVariable
2735 if (EFI_ERROR (Status
)) {
2739 mVariableModuleGlobal
->VolatileLastVariableOffset
+= HEADER_ALIGN (VarSize
);
2743 // Mark the old variable as deleted.
2745 if (!EFI_ERROR (Status
) && Variable
->CurrPtr
!= NULL
) {
2746 if (Variable
->InDeletedTransitionPtr
!= NULL
) {
2748 // Both ADDED and IN_DELETED_TRANSITION old variable are present,
2749 // set IN_DELETED_TRANSITION one to DELETED state first.
2751 ASSERT (CacheVariable
->InDeletedTransitionPtr
!= NULL
);
2752 State
= CacheVariable
->InDeletedTransitionPtr
->State
;
2753 State
&= VAR_DELETED
;
2754 Status
= UpdateVariableStore (
2755 &mVariableModuleGlobal
->VariableGlobal
,
2759 (UINTN
) &Variable
->InDeletedTransitionPtr
->State
,
2763 if (!EFI_ERROR (Status
)) {
2764 if (!Variable
->Volatile
) {
2765 CacheVariable
->InDeletedTransitionPtr
->State
= State
;
2772 State
= Variable
->CurrPtr
->State
;
2773 State
&= VAR_DELETED
;
2775 Status
= UpdateVariableStore (
2776 &mVariableModuleGlobal
->VariableGlobal
,
2780 (UINTN
) &Variable
->CurrPtr
->State
,
2784 if (!EFI_ERROR (Status
) && !Variable
->Volatile
) {
2785 CacheVariable
->CurrPtr
->State
= State
;
2789 if (!EFI_ERROR (Status
)) {
2790 UpdateVariableInfo (VariableName
, VendorGuid
, Volatile
, FALSE
, TRUE
, FALSE
, FALSE
);
2792 FlushHobVariableToFlash (VariableName
, VendorGuid
);
2802 This code finds variable in storage blocks (Volatile or Non-Volatile).
2804 Caution: This function may receive untrusted input.
2805 This function may be invoked in SMM mode, and datasize is external input.
2806 This function will do basic validation, before parse the data.
2808 @param VariableName Name of Variable to be found.
2809 @param VendorGuid Variable vendor GUID.
2810 @param Attributes Attribute value of the variable found.
2811 @param DataSize Size of Data found. If size is less than the
2812 data, this value contains the required size.
2813 @param Data The buffer to return the contents of the variable. May be NULL
2814 with a zero DataSize in order to determine the size buffer needed.
2816 @return EFI_INVALID_PARAMETER Invalid parameter.
2817 @return EFI_SUCCESS Find the specified variable.
2818 @return EFI_NOT_FOUND Not found.
2819 @return EFI_BUFFER_TO_SMALL DataSize is too small for the result.
2824 VariableServiceGetVariable (
2825 IN CHAR16
*VariableName
,
2826 IN EFI_GUID
*VendorGuid
,
2827 OUT UINT32
*Attributes OPTIONAL
,
2828 IN OUT UINTN
*DataSize
,
2829 OUT VOID
*Data OPTIONAL
2833 VARIABLE_POINTER_TRACK Variable
;
2836 if (VariableName
== NULL
|| VendorGuid
== NULL
|| DataSize
== NULL
) {
2837 return EFI_INVALID_PARAMETER
;
2840 if (VariableName
[0] == 0) {
2841 return EFI_NOT_FOUND
;
2844 AcquireLockOnlyAtBootTime(&mVariableModuleGlobal
->VariableGlobal
.VariableServicesLock
);
2846 Status
= FindVariable (VariableName
, VendorGuid
, &Variable
, &mVariableModuleGlobal
->VariableGlobal
, FALSE
);
2847 if (Variable
.CurrPtr
== NULL
|| EFI_ERROR (Status
)) {
2854 VarDataSize
= DataSizeOfVariable (Variable
.CurrPtr
);
2855 ASSERT (VarDataSize
!= 0);
2857 if (*DataSize
>= VarDataSize
) {
2859 Status
= EFI_INVALID_PARAMETER
;
2863 CopyMem (Data
, GetVariableDataPtr (Variable
.CurrPtr
), VarDataSize
);
2864 if (Attributes
!= NULL
) {
2865 *Attributes
= Variable
.CurrPtr
->Attributes
;
2868 *DataSize
= VarDataSize
;
2869 UpdateVariableInfo (VariableName
, VendorGuid
, Variable
.Volatile
, TRUE
, FALSE
, FALSE
, FALSE
);
2871 Status
= EFI_SUCCESS
;
2874 *DataSize
= VarDataSize
;
2875 Status
= EFI_BUFFER_TOO_SMALL
;
2880 ReleaseLockOnlyAtBootTime (&mVariableModuleGlobal
->VariableGlobal
.VariableServicesLock
);
2885 This code Finds the Next available variable.
2887 Caution: This function may receive untrusted input.
2888 This function may be invoked in SMM mode. This function will do basic validation, before parse the data.
2890 @param[in] VariableName Pointer to variable name.
2891 @param[in] VendorGuid Variable Vendor Guid.
2892 @param[out] VariablePtr Pointer to variable header address.
2894 @retval EFI_SUCCESS The function completed successfully.
2895 @retval EFI_NOT_FOUND The next variable was not found.
2896 @retval EFI_INVALID_PARAMETER If VariableName is not an empty string, while VendorGuid is NULL.
2897 @retval EFI_INVALID_PARAMETER The input values of VariableName and VendorGuid are not a name and
2898 GUID of an existing variable.
2903 VariableServiceGetNextVariableInternal (
2904 IN CHAR16
*VariableName
,
2905 IN EFI_GUID
*VendorGuid
,
2906 OUT VARIABLE_HEADER
**VariablePtr
2909 VARIABLE_STORE_TYPE Type
;
2910 VARIABLE_POINTER_TRACK Variable
;
2911 VARIABLE_POINTER_TRACK VariableInHob
;
2912 VARIABLE_POINTER_TRACK VariablePtrTrack
;
2914 VARIABLE_STORE_HEADER
*VariableStoreHeader
[VariableStoreTypeMax
];
2916 Status
= FindVariable (VariableName
, VendorGuid
, &Variable
, &mVariableModuleGlobal
->VariableGlobal
, FALSE
);
2917 if (Variable
.CurrPtr
== NULL
|| EFI_ERROR (Status
)) {
2919 // For VariableName is an empty string, FindVariable() will try to find and return
2920 // the first qualified variable, and if FindVariable() returns error (EFI_NOT_FOUND)
2921 // as no any variable is found, still go to return the error (EFI_NOT_FOUND).
2923 if (VariableName
[0] != 0) {
2925 // For VariableName is not an empty string, and FindVariable() returns error as
2926 // VariableName and VendorGuid are not a name and GUID of an existing variable,
2927 // there is no way to get next variable, follow spec to return EFI_INVALID_PARAMETER.
2929 Status
= EFI_INVALID_PARAMETER
;
2934 if (VariableName
[0] != 0) {
2936 // If variable name is not NULL, get next variable.
2938 Variable
.CurrPtr
= GetNextVariablePtr (Variable
.CurrPtr
);
2942 // 0: Volatile, 1: HOB, 2: Non-Volatile.
2943 // The index and attributes mapping must be kept in this order as FindVariable
2944 // makes use of this mapping to implement search algorithm.
2946 VariableStoreHeader
[VariableStoreTypeVolatile
] = (VARIABLE_STORE_HEADER
*) (UINTN
) mVariableModuleGlobal
->VariableGlobal
.VolatileVariableBase
;
2947 VariableStoreHeader
[VariableStoreTypeHob
] = (VARIABLE_STORE_HEADER
*) (UINTN
) mVariableModuleGlobal
->VariableGlobal
.HobVariableBase
;
2948 VariableStoreHeader
[VariableStoreTypeNv
] = mNvVariableCache
;
2952 // Switch from Volatile to HOB, to Non-Volatile.
2954 while (!IsValidVariableHeader (Variable
.CurrPtr
, Variable
.EndPtr
)) {
2956 // Find current storage index
2958 for (Type
= (VARIABLE_STORE_TYPE
) 0; Type
< VariableStoreTypeMax
; Type
++) {
2959 if ((VariableStoreHeader
[Type
] != NULL
) && (Variable
.StartPtr
== GetStartPointer (VariableStoreHeader
[Type
]))) {
2963 ASSERT (Type
< VariableStoreTypeMax
);
2965 // Switch to next storage
2967 for (Type
++; Type
< VariableStoreTypeMax
; Type
++) {
2968 if (VariableStoreHeader
[Type
] != NULL
) {
2973 // Capture the case that
2974 // 1. current storage is the last one, or
2975 // 2. no further storage
2977 if (Type
== VariableStoreTypeMax
) {
2978 Status
= EFI_NOT_FOUND
;
2981 Variable
.StartPtr
= GetStartPointer (VariableStoreHeader
[Type
]);
2982 Variable
.EndPtr
= GetEndPointer (VariableStoreHeader
[Type
]);
2983 Variable
.CurrPtr
= Variable
.StartPtr
;
2987 // Variable is found
2989 if (Variable
.CurrPtr
->State
== VAR_ADDED
|| Variable
.CurrPtr
->State
== (VAR_IN_DELETED_TRANSITION
& VAR_ADDED
)) {
2990 if (!AtRuntime () || ((Variable
.CurrPtr
->Attributes
& EFI_VARIABLE_RUNTIME_ACCESS
) != 0)) {
2991 if (Variable
.CurrPtr
->State
== (VAR_IN_DELETED_TRANSITION
& VAR_ADDED
)) {
2993 // If it is a IN_DELETED_TRANSITION variable,
2994 // and there is also a same ADDED one at the same time,
2997 VariablePtrTrack
.StartPtr
= Variable
.StartPtr
;
2998 VariablePtrTrack
.EndPtr
= Variable
.EndPtr
;
2999 Status
= FindVariableEx (
3000 GetVariableNamePtr (Variable
.CurrPtr
),
3001 GetVendorGuidPtr (Variable
.CurrPtr
),
3005 if (!EFI_ERROR (Status
) && VariablePtrTrack
.CurrPtr
->State
== VAR_ADDED
) {
3006 Variable
.CurrPtr
= GetNextVariablePtr (Variable
.CurrPtr
);
3012 // Don't return NV variable when HOB overrides it
3014 if ((VariableStoreHeader
[VariableStoreTypeHob
] != NULL
) && (VariableStoreHeader
[VariableStoreTypeNv
] != NULL
) &&
3015 (Variable
.StartPtr
== GetStartPointer (VariableStoreHeader
[VariableStoreTypeNv
]))
3017 VariableInHob
.StartPtr
= GetStartPointer (VariableStoreHeader
[VariableStoreTypeHob
]);
3018 VariableInHob
.EndPtr
= GetEndPointer (VariableStoreHeader
[VariableStoreTypeHob
]);
3019 Status
= FindVariableEx (
3020 GetVariableNamePtr (Variable
.CurrPtr
),
3021 GetVendorGuidPtr (Variable
.CurrPtr
),
3025 if (!EFI_ERROR (Status
)) {
3026 Variable
.CurrPtr
= GetNextVariablePtr (Variable
.CurrPtr
);
3031 *VariablePtr
= Variable
.CurrPtr
;
3032 Status
= EFI_SUCCESS
;
3037 Variable
.CurrPtr
= GetNextVariablePtr (Variable
.CurrPtr
);
3046 This code Finds the Next available variable.
3048 Caution: This function may receive untrusted input.
3049 This function may be invoked in SMM mode. This function will do basic validation, before parse the data.
3051 @param VariableNameSize The size of the VariableName buffer. The size must be large
3052 enough to fit input string supplied in VariableName buffer.
3053 @param VariableName Pointer to variable name.
3054 @param VendorGuid Variable Vendor Guid.
3056 @retval EFI_SUCCESS The function completed successfully.
3057 @retval EFI_NOT_FOUND The next variable was not found.
3058 @retval EFI_BUFFER_TOO_SMALL The VariableNameSize is too small for the result.
3059 VariableNameSize has been updated with the size needed to complete the request.
3060 @retval EFI_INVALID_PARAMETER VariableNameSize is NULL.
3061 @retval EFI_INVALID_PARAMETER VariableName is NULL.
3062 @retval EFI_INVALID_PARAMETER VendorGuid is NULL.
3063 @retval EFI_INVALID_PARAMETER The input values of VariableName and VendorGuid are not a name and
3064 GUID of an existing variable.
3065 @retval EFI_INVALID_PARAMETER Null-terminator is not found in the first VariableNameSize bytes of
3066 the input VariableName buffer.
3071 VariableServiceGetNextVariableName (
3072 IN OUT UINTN
*VariableNameSize
,
3073 IN OUT CHAR16
*VariableName
,
3074 IN OUT EFI_GUID
*VendorGuid
3080 VARIABLE_HEADER
*VariablePtr
;
3082 if (VariableNameSize
== NULL
|| VariableName
== NULL
|| VendorGuid
== NULL
) {
3083 return EFI_INVALID_PARAMETER
;
3087 // Calculate the possible maximum length of name string, including the Null terminator.
3089 MaxLen
= *VariableNameSize
/ sizeof (CHAR16
);
3090 if ((MaxLen
== 0) || (StrnLenS (VariableName
, MaxLen
) == MaxLen
)) {
3092 // Null-terminator is not found in the first VariableNameSize bytes of the input VariableName buffer,
3093 // follow spec to return EFI_INVALID_PARAMETER.
3095 return EFI_INVALID_PARAMETER
;
3098 AcquireLockOnlyAtBootTime(&mVariableModuleGlobal
->VariableGlobal
.VariableServicesLock
);
3100 Status
= VariableServiceGetNextVariableInternal (VariableName
, VendorGuid
, &VariablePtr
);
3101 if (!EFI_ERROR (Status
)) {
3102 VarNameSize
= NameSizeOfVariable (VariablePtr
);
3103 ASSERT (VarNameSize
!= 0);
3104 if (VarNameSize
<= *VariableNameSize
) {
3105 CopyMem (VariableName
, GetVariableNamePtr (VariablePtr
), VarNameSize
);
3106 CopyMem (VendorGuid
, GetVendorGuidPtr (VariablePtr
), sizeof (EFI_GUID
));
3107 Status
= EFI_SUCCESS
;
3109 Status
= EFI_BUFFER_TOO_SMALL
;
3112 *VariableNameSize
= VarNameSize
;
3115 ReleaseLockOnlyAtBootTime (&mVariableModuleGlobal
->VariableGlobal
.VariableServicesLock
);
3121 This code sets variable in storage blocks (Volatile or Non-Volatile).
3123 Caution: This function may receive untrusted input.
3124 This function may be invoked in SMM mode, and datasize and data are external input.
3125 This function will do basic validation, before parse the data.
3126 This function will parse the authentication carefully to avoid security issues, like
3127 buffer overflow, integer overflow.
3128 This function will check attribute carefully to avoid authentication bypass.
3130 @param VariableName Name of Variable to be found.
3131 @param VendorGuid Variable vendor GUID.
3132 @param Attributes Attribute value of the variable found
3133 @param DataSize Size of Data found. If size is less than the
3134 data, this value contains the required size.
3135 @param Data Data pointer.
3137 @return EFI_INVALID_PARAMETER Invalid parameter.
3138 @return EFI_SUCCESS Set successfully.
3139 @return EFI_OUT_OF_RESOURCES Resource not enough to set variable.
3140 @return EFI_NOT_FOUND Not found.
3141 @return EFI_WRITE_PROTECTED Variable is read-only.
3146 VariableServiceSetVariable (
3147 IN CHAR16
*VariableName
,
3148 IN EFI_GUID
*VendorGuid
,
3149 IN UINT32 Attributes
,
3154 VARIABLE_POINTER_TRACK Variable
;
3156 VARIABLE_HEADER
*NextVariable
;
3157 EFI_PHYSICAL_ADDRESS Point
;
3161 // Check input parameters.
3163 if (VariableName
== NULL
|| VariableName
[0] == 0 || VendorGuid
== NULL
) {
3164 return EFI_INVALID_PARAMETER
;
3167 if (DataSize
!= 0 && Data
== NULL
) {
3168 return EFI_INVALID_PARAMETER
;
3172 // Check for reserverd bit in variable attribute.
3174 if ((Attributes
& (~EFI_VARIABLE_ATTRIBUTES_MASK
)) != 0) {
3175 return EFI_INVALID_PARAMETER
;
3179 // Make sure if runtime bit is set, boot service bit is set also.
3181 if ((Attributes
& (EFI_VARIABLE_RUNTIME_ACCESS
| EFI_VARIABLE_BOOTSERVICE_ACCESS
)) == EFI_VARIABLE_RUNTIME_ACCESS
) {
3182 return EFI_INVALID_PARAMETER
;
3183 } else if ((Attributes
& VARIABLE_ATTRIBUTE_AT_AW
) != 0) {
3184 if (!mVariableModuleGlobal
->VariableGlobal
.AuthSupport
) {
3186 // Not support authenticated variable write.
3188 return EFI_INVALID_PARAMETER
;
3190 } else if ((Attributes
& EFI_VARIABLE_HARDWARE_ERROR_RECORD
) != 0) {
3191 if (PcdGet32 (PcdHwErrStorageSize
) == 0) {
3193 // Not support harware error record variable variable.
3195 return EFI_INVALID_PARAMETER
;
3200 // EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS and EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS attribute
3201 // cannot be set both.
3203 if (((Attributes
& EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS
) == EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS
)
3204 && ((Attributes
& EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS
) == EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS
)) {
3205 return EFI_INVALID_PARAMETER
;
3208 if ((Attributes
& EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS
) == EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS
) {
3209 if (DataSize
< AUTHINFO_SIZE
) {
3211 // Try to write Authenticated Variable without AuthInfo.
3213 return EFI_SECURITY_VIOLATION
;
3215 PayloadSize
= DataSize
- AUTHINFO_SIZE
;
3216 } else if ((Attributes
& EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS
) == EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS
) {
3218 // Sanity check for EFI_VARIABLE_AUTHENTICATION_2 descriptor.
3220 if (DataSize
< OFFSET_OF_AUTHINFO2_CERT_DATA
||
3221 ((EFI_VARIABLE_AUTHENTICATION_2
*) Data
)->AuthInfo
.Hdr
.dwLength
> DataSize
- (OFFSET_OF (EFI_VARIABLE_AUTHENTICATION_2
, AuthInfo
)) ||
3222 ((EFI_VARIABLE_AUTHENTICATION_2
*) Data
)->AuthInfo
.Hdr
.dwLength
< OFFSET_OF (WIN_CERTIFICATE_UEFI_GUID
, CertData
)) {
3223 return EFI_SECURITY_VIOLATION
;
3225 PayloadSize
= DataSize
- AUTHINFO2_SIZE (Data
);
3227 PayloadSize
= DataSize
;
3230 if ((UINTN
)(~0) - PayloadSize
< StrSize(VariableName
)){
3232 // Prevent whole variable size overflow
3234 return EFI_INVALID_PARAMETER
;
3238 // The size of the VariableName, including the Unicode Null in bytes plus
3239 // the DataSize is limited to maximum size of PcdGet32 (PcdMaxHardwareErrorVariableSize)
3240 // bytes for HwErrRec#### variable.
3242 if ((Attributes
& EFI_VARIABLE_HARDWARE_ERROR_RECORD
) == EFI_VARIABLE_HARDWARE_ERROR_RECORD
) {
3243 if (StrSize (VariableName
) + PayloadSize
> PcdGet32 (PcdMaxHardwareErrorVariableSize
) - GetVariableHeaderSize ()) {
3244 return EFI_INVALID_PARAMETER
;
3248 // The size of the VariableName, including the Unicode Null in bytes plus
3249 // the DataSize is limited to maximum size of Max(Auth)VariableSize bytes.
3251 if ((Attributes
& VARIABLE_ATTRIBUTE_AT_AW
) != 0) {
3252 if (StrSize (VariableName
) + PayloadSize
> mVariableModuleGlobal
->MaxAuthVariableSize
- GetVariableHeaderSize ()) {
3253 return EFI_INVALID_PARAMETER
;
3256 if (StrSize (VariableName
) + PayloadSize
> mVariableModuleGlobal
->MaxVariableSize
- GetVariableHeaderSize ()) {
3257 return EFI_INVALID_PARAMETER
;
3263 // Special Handling for MOR Lock variable.
3265 Status
= SetVariableCheckHandlerMor (VariableName
, VendorGuid
, Attributes
, PayloadSize
, (VOID
*) ((UINTN
) Data
+ DataSize
- PayloadSize
));
3266 if (Status
== EFI_ALREADY_STARTED
) {
3268 // EFI_ALREADY_STARTED means the SetVariable() action is handled inside of SetVariableCheckHandlerMor().
3269 // Variable driver can just return SUCCESS.
3273 if (EFI_ERROR (Status
)) {
3277 Status
= VarCheckLibSetVariableCheck (VariableName
, VendorGuid
, Attributes
, PayloadSize
, (VOID
*) ((UINTN
) Data
+ DataSize
- PayloadSize
), mRequestSource
);
3278 if (EFI_ERROR (Status
)) {
3282 AcquireLockOnlyAtBootTime(&mVariableModuleGlobal
->VariableGlobal
.VariableServicesLock
);
3285 // Consider reentrant in MCA/INIT/NMI. It needs be reupdated.
3287 if (1 < InterlockedIncrement (&mVariableModuleGlobal
->VariableGlobal
.ReentrantState
)) {
3288 Point
= mVariableModuleGlobal
->VariableGlobal
.NonVolatileVariableBase
;
3290 // Parse non-volatile variable data and get last variable offset.
3292 NextVariable
= GetStartPointer ((VARIABLE_STORE_HEADER
*) (UINTN
) Point
);
3293 while (IsValidVariableHeader (NextVariable
, GetEndPointer ((VARIABLE_STORE_HEADER
*) (UINTN
) Point
))) {
3294 NextVariable
= GetNextVariablePtr (NextVariable
);
3296 mVariableModuleGlobal
->NonVolatileLastVariableOffset
= (UINTN
) NextVariable
- (UINTN
) Point
;
3300 // Check whether the input variable is already existed.
3302 Status
= FindVariable (VariableName
, VendorGuid
, &Variable
, &mVariableModuleGlobal
->VariableGlobal
, TRUE
);
3303 if (!EFI_ERROR (Status
)) {
3304 if (((Variable
.CurrPtr
->Attributes
& EFI_VARIABLE_RUNTIME_ACCESS
) == 0) && AtRuntime ()) {
3305 Status
= EFI_WRITE_PROTECTED
;
3308 if (Attributes
!= 0 && (Attributes
& (~EFI_VARIABLE_APPEND_WRITE
)) != Variable
.CurrPtr
->Attributes
) {
3310 // If a preexisting variable is rewritten with different attributes, SetVariable() shall not
3311 // modify the variable and shall return EFI_INVALID_PARAMETER. Two exceptions to this rule:
3312 // 1. No access attributes specified
3313 // 2. The only attribute differing is EFI_VARIABLE_APPEND_WRITE
3315 Status
= EFI_INVALID_PARAMETER
;
3316 DEBUG ((EFI_D_INFO
, "[Variable]: Rewritten a preexisting variable(0x%08x) with different attributes(0x%08x) - %g:%s\n", Variable
.CurrPtr
->Attributes
, Attributes
, VendorGuid
, VariableName
));
3321 if (!FeaturePcdGet (PcdUefiVariableDefaultLangDeprecate
)) {
3323 // Hook the operation of setting PlatformLangCodes/PlatformLang and LangCodes/Lang.
3325 Status
= AutoUpdateLangVariable (VariableName
, Data
, DataSize
);
3326 if (EFI_ERROR (Status
)) {
3328 // The auto update operation failed, directly return to avoid inconsistency between PlatformLang and Lang.
3334 if (mVariableModuleGlobal
->VariableGlobal
.AuthSupport
) {
3335 Status
= AuthVariableLibProcessVariable (VariableName
, VendorGuid
, Data
, DataSize
, Attributes
);
3337 Status
= UpdateVariable (VariableName
, VendorGuid
, Data
, DataSize
, Attributes
, 0, 0, &Variable
, NULL
);
3341 InterlockedDecrement (&mVariableModuleGlobal
->VariableGlobal
.ReentrantState
);
3342 ReleaseLockOnlyAtBootTime (&mVariableModuleGlobal
->VariableGlobal
.VariableServicesLock
);
3344 if (!AtRuntime ()) {
3345 if (!EFI_ERROR (Status
)) {
3358 This code returns information about the EFI variables.
3360 Caution: This function may receive untrusted input.
3361 This function may be invoked in SMM mode. This function will do basic validation, before parse the data.
3363 @param Attributes Attributes bitmask to specify the type of variables
3364 on which to return information.
3365 @param MaximumVariableStorageSize Pointer to the maximum size of the storage space available
3366 for the EFI variables associated with the attributes specified.
3367 @param RemainingVariableStorageSize Pointer to the remaining size of the storage space available
3368 for EFI variables associated with the attributes specified.
3369 @param MaximumVariableSize Pointer to the maximum size of an individual EFI variables
3370 associated with the attributes specified.
3372 @return EFI_SUCCESS Query successfully.
3377 VariableServiceQueryVariableInfoInternal (
3378 IN UINT32 Attributes
,
3379 OUT UINT64
*MaximumVariableStorageSize
,
3380 OUT UINT64
*RemainingVariableStorageSize
,
3381 OUT UINT64
*MaximumVariableSize
3384 VARIABLE_HEADER
*Variable
;
3385 VARIABLE_HEADER
*NextVariable
;
3386 UINT64 VariableSize
;
3387 VARIABLE_STORE_HEADER
*VariableStoreHeader
;
3388 UINT64 CommonVariableTotalSize
;
3389 UINT64 HwErrVariableTotalSize
;
3391 VARIABLE_POINTER_TRACK VariablePtrTrack
;
3393 CommonVariableTotalSize
= 0;
3394 HwErrVariableTotalSize
= 0;
3396 if((Attributes
& EFI_VARIABLE_NON_VOLATILE
) == 0) {
3398 // Query is Volatile related.
3400 VariableStoreHeader
= (VARIABLE_STORE_HEADER
*) ((UINTN
) mVariableModuleGlobal
->VariableGlobal
.VolatileVariableBase
);
3403 // Query is Non-Volatile related.
3405 VariableStoreHeader
= mNvVariableCache
;
3409 // Now let's fill *MaximumVariableStorageSize *RemainingVariableStorageSize
3410 // with the storage size (excluding the storage header size).
3412 *MaximumVariableStorageSize
= VariableStoreHeader
->Size
- sizeof (VARIABLE_STORE_HEADER
);
3415 // Harware error record variable needs larger size.
3417 if ((Attributes
& (EFI_VARIABLE_NON_VOLATILE
| EFI_VARIABLE_HARDWARE_ERROR_RECORD
)) == (EFI_VARIABLE_NON_VOLATILE
| EFI_VARIABLE_HARDWARE_ERROR_RECORD
)) {
3418 *MaximumVariableStorageSize
= PcdGet32 (PcdHwErrStorageSize
);
3419 *MaximumVariableSize
= PcdGet32 (PcdMaxHardwareErrorVariableSize
) - GetVariableHeaderSize ();
3421 if ((Attributes
& EFI_VARIABLE_NON_VOLATILE
) != 0) {
3423 *MaximumVariableStorageSize
= mVariableModuleGlobal
->CommonRuntimeVariableSpace
;
3425 *MaximumVariableStorageSize
= mVariableModuleGlobal
->CommonVariableSpace
;
3430 // Let *MaximumVariableSize be Max(Auth)VariableSize with the exception of the variable header size.
3432 if ((Attributes
& VARIABLE_ATTRIBUTE_AT_AW
) != 0) {
3433 *MaximumVariableSize
= mVariableModuleGlobal
->MaxAuthVariableSize
- GetVariableHeaderSize ();
3435 *MaximumVariableSize
= mVariableModuleGlobal
->MaxVariableSize
- GetVariableHeaderSize ();
3440 // Point to the starting address of the variables.
3442 Variable
= GetStartPointer (VariableStoreHeader
);
3445 // Now walk through the related variable store.
3447 while (IsValidVariableHeader (Variable
, GetEndPointer (VariableStoreHeader
))) {
3448 NextVariable
= GetNextVariablePtr (Variable
);
3449 VariableSize
= (UINT64
) (UINTN
) NextVariable
- (UINT64
) (UINTN
) Variable
;
3453 // We don't take the state of the variables in mind
3454 // when calculating RemainingVariableStorageSize,
3455 // since the space occupied by variables not marked with
3456 // VAR_ADDED is not allowed to be reclaimed in Runtime.
3458 if ((Variable
->Attributes
& EFI_VARIABLE_HARDWARE_ERROR_RECORD
) == EFI_VARIABLE_HARDWARE_ERROR_RECORD
) {
3459 HwErrVariableTotalSize
+= VariableSize
;
3461 CommonVariableTotalSize
+= VariableSize
;
3465 // Only care about Variables with State VAR_ADDED, because
3466 // the space not marked as VAR_ADDED is reclaimable now.
3468 if (Variable
->State
== VAR_ADDED
) {
3469 if ((Variable
->Attributes
& EFI_VARIABLE_HARDWARE_ERROR_RECORD
) == EFI_VARIABLE_HARDWARE_ERROR_RECORD
) {
3470 HwErrVariableTotalSize
+= VariableSize
;
3472 CommonVariableTotalSize
+= VariableSize
;
3474 } else if (Variable
->State
== (VAR_IN_DELETED_TRANSITION
& VAR_ADDED
)) {
3476 // If it is a IN_DELETED_TRANSITION variable,
3477 // and there is not also a same ADDED one at the same time,
3478 // this IN_DELETED_TRANSITION variable is valid.
3480 VariablePtrTrack
.StartPtr
= GetStartPointer (VariableStoreHeader
);
3481 VariablePtrTrack
.EndPtr
= GetEndPointer (VariableStoreHeader
);
3482 Status
= FindVariableEx (
3483 GetVariableNamePtr (Variable
),
3484 GetVendorGuidPtr (Variable
),
3488 if (!EFI_ERROR (Status
) && VariablePtrTrack
.CurrPtr
->State
!= VAR_ADDED
) {
3489 if ((Variable
->Attributes
& EFI_VARIABLE_HARDWARE_ERROR_RECORD
) == EFI_VARIABLE_HARDWARE_ERROR_RECORD
) {
3490 HwErrVariableTotalSize
+= VariableSize
;
3492 CommonVariableTotalSize
+= VariableSize
;
3499 // Go to the next one.
3501 Variable
= NextVariable
;
3504 if ((Attributes
& EFI_VARIABLE_HARDWARE_ERROR_RECORD
) == EFI_VARIABLE_HARDWARE_ERROR_RECORD
){
3505 *RemainingVariableStorageSize
= *MaximumVariableStorageSize
- HwErrVariableTotalSize
;
3507 if (*MaximumVariableStorageSize
< CommonVariableTotalSize
) {
3508 *RemainingVariableStorageSize
= 0;
3510 *RemainingVariableStorageSize
= *MaximumVariableStorageSize
- CommonVariableTotalSize
;
3514 if (*RemainingVariableStorageSize
< GetVariableHeaderSize ()) {
3515 *MaximumVariableSize
= 0;
3516 } else if ((*RemainingVariableStorageSize
- GetVariableHeaderSize ()) < *MaximumVariableSize
) {
3517 *MaximumVariableSize
= *RemainingVariableStorageSize
- GetVariableHeaderSize ();
3525 This code returns information about the EFI variables.
3527 Caution: This function may receive untrusted input.
3528 This function may be invoked in SMM mode. This function will do basic validation, before parse the data.
3530 @param Attributes Attributes bitmask to specify the type of variables
3531 on which to return information.
3532 @param MaximumVariableStorageSize Pointer to the maximum size of the storage space available
3533 for the EFI variables associated with the attributes specified.
3534 @param RemainingVariableStorageSize Pointer to the remaining size of the storage space available
3535 for EFI variables associated with the attributes specified.
3536 @param MaximumVariableSize Pointer to the maximum size of an individual EFI variables
3537 associated with the attributes specified.
3539 @return EFI_INVALID_PARAMETER An invalid combination of attribute bits was supplied.
3540 @return EFI_SUCCESS Query successfully.
3541 @return EFI_UNSUPPORTED The attribute is not supported on this platform.
3546 VariableServiceQueryVariableInfo (
3547 IN UINT32 Attributes
,
3548 OUT UINT64
*MaximumVariableStorageSize
,
3549 OUT UINT64
*RemainingVariableStorageSize
,
3550 OUT UINT64
*MaximumVariableSize
3555 if(MaximumVariableStorageSize
== NULL
|| RemainingVariableStorageSize
== NULL
|| MaximumVariableSize
== NULL
|| Attributes
== 0) {
3556 return EFI_INVALID_PARAMETER
;
3559 if ((Attributes
& EFI_VARIABLE_ATTRIBUTES_MASK
) == 0) {
3561 // Make sure the Attributes combination is supported by the platform.
3563 return EFI_UNSUPPORTED
;
3564 } else if ((Attributes
& (EFI_VARIABLE_RUNTIME_ACCESS
| EFI_VARIABLE_BOOTSERVICE_ACCESS
)) == EFI_VARIABLE_RUNTIME_ACCESS
) {
3566 // Make sure if runtime bit is set, boot service bit is set also.
3568 return EFI_INVALID_PARAMETER
;
3569 } else if (AtRuntime () && ((Attributes
& EFI_VARIABLE_RUNTIME_ACCESS
) == 0)) {
3571 // Make sure RT Attribute is set if we are in Runtime phase.
3573 return EFI_INVALID_PARAMETER
;
3574 } else if ((Attributes
& (EFI_VARIABLE_NON_VOLATILE
| EFI_VARIABLE_HARDWARE_ERROR_RECORD
)) == EFI_VARIABLE_HARDWARE_ERROR_RECORD
) {
3576 // Make sure Hw Attribute is set with NV.
3578 return EFI_INVALID_PARAMETER
;
3579 } else if ((Attributes
& VARIABLE_ATTRIBUTE_AT_AW
) != 0) {
3580 if (!mVariableModuleGlobal
->VariableGlobal
.AuthSupport
) {
3582 // Not support authenticated variable write.
3584 return EFI_UNSUPPORTED
;
3586 } else if ((Attributes
& EFI_VARIABLE_HARDWARE_ERROR_RECORD
) != 0) {
3587 if (PcdGet32 (PcdHwErrStorageSize
) == 0) {
3589 // Not support harware error record variable variable.
3591 return EFI_UNSUPPORTED
;
3595 AcquireLockOnlyAtBootTime(&mVariableModuleGlobal
->VariableGlobal
.VariableServicesLock
);
3597 Status
= VariableServiceQueryVariableInfoInternal (
3599 MaximumVariableStorageSize
,
3600 RemainingVariableStorageSize
,
3604 ReleaseLockOnlyAtBootTime (&mVariableModuleGlobal
->VariableGlobal
.VariableServicesLock
);
3609 This function reclaims variable storage if free size is below the threshold.
3611 Caution: This function may be invoked at SMM mode.
3612 Care must be taken to make sure not security issue.
3621 UINTN RemainingCommonRuntimeVariableSpace
;
3622 UINTN RemainingHwErrVariableSpace
;
3623 STATIC BOOLEAN Reclaimed
;
3626 // This function will be called only once at EndOfDxe or ReadyToBoot event.
3633 Status
= EFI_SUCCESS
;
3635 if (mVariableModuleGlobal
->CommonRuntimeVariableSpace
< mVariableModuleGlobal
->CommonVariableTotalSize
) {
3636 RemainingCommonRuntimeVariableSpace
= 0;
3638 RemainingCommonRuntimeVariableSpace
= mVariableModuleGlobal
->CommonRuntimeVariableSpace
- mVariableModuleGlobal
->CommonVariableTotalSize
;
3641 RemainingHwErrVariableSpace
= PcdGet32 (PcdHwErrStorageSize
) - mVariableModuleGlobal
->HwErrVariableTotalSize
;
3644 // Check if the free area is below a threshold.
3646 if (((RemainingCommonRuntimeVariableSpace
< mVariableModuleGlobal
->MaxVariableSize
) ||
3647 (RemainingCommonRuntimeVariableSpace
< mVariableModuleGlobal
->MaxAuthVariableSize
)) ||
3648 ((PcdGet32 (PcdHwErrStorageSize
) != 0) &&
3649 (RemainingHwErrVariableSpace
< PcdGet32 (PcdMaxHardwareErrorVariableSize
)))){
3651 mVariableModuleGlobal
->VariableGlobal
.NonVolatileVariableBase
,
3652 &mVariableModuleGlobal
->NonVolatileLastVariableOffset
,
3658 ASSERT_EFI_ERROR (Status
);
3663 Get non-volatile maximum variable size.
3665 @return Non-volatile maximum variable size.
3669 GetNonVolatileMaxVariableSize (
3673 if (PcdGet32 (PcdHwErrStorageSize
) != 0) {
3674 return MAX (MAX (PcdGet32 (PcdMaxVariableSize
), PcdGet32 (PcdMaxAuthVariableSize
)),
3675 PcdGet32 (PcdMaxHardwareErrorVariableSize
));
3677 return MAX (PcdGet32 (PcdMaxVariableSize
), PcdGet32 (PcdMaxAuthVariableSize
));
3682 Init non-volatile variable store.
3684 @param[out] NvFvHeader Output pointer to non-volatile FV header address.
3686 @retval EFI_SUCCESS Function successfully executed.
3687 @retval EFI_OUT_OF_RESOURCES Fail to allocate enough memory resource.
3688 @retval EFI_VOLUME_CORRUPTED Variable Store or Firmware Volume for Variable Store is corrupted.
3692 InitNonVolatileVariableStore (
3693 OUT EFI_FIRMWARE_VOLUME_HEADER
**NvFvHeader
3696 EFI_FIRMWARE_VOLUME_HEADER
*FvHeader
;
3697 VARIABLE_HEADER
*Variable
;
3698 VARIABLE_HEADER
*NextVariable
;
3699 EFI_PHYSICAL_ADDRESS VariableStoreBase
;
3700 UINT64 VariableStoreLength
;
3702 EFI_HOB_GUID_TYPE
*GuidHob
;
3703 EFI_PHYSICAL_ADDRESS NvStorageBase
;
3704 UINT8
*NvStorageData
;
3705 UINT32 NvStorageSize
;
3706 FAULT_TOLERANT_WRITE_LAST_WRITE_DATA
*FtwLastWriteData
;
3707 UINT32 BackUpOffset
;
3709 UINT32 HwErrStorageSize
;
3710 UINT32 MaxUserNvVariableSpaceSize
;
3711 UINT32 BoottimeReservedNvVariableSpaceSize
;
3715 mVariableModuleGlobal
->FvbInstance
= NULL
;
3718 // Allocate runtime memory used for a memory copy of the FLASH region.
3719 // Keep the memory and the FLASH in sync as updates occur.
3721 NvStorageSize
= PcdGet32 (PcdFlashNvStorageVariableSize
);
3722 NvStorageData
= AllocateRuntimeZeroPool (NvStorageSize
);
3723 if (NvStorageData
== NULL
) {
3724 return EFI_OUT_OF_RESOURCES
;
3727 NvStorageBase
= (EFI_PHYSICAL_ADDRESS
) PcdGet64 (PcdFlashNvStorageVariableBase64
);
3728 if (NvStorageBase
== 0) {
3729 NvStorageBase
= (EFI_PHYSICAL_ADDRESS
) PcdGet32 (PcdFlashNvStorageVariableBase
);
3732 // Copy NV storage data to the memory buffer.
3734 CopyMem (NvStorageData
, (UINT8
*) (UINTN
) NvStorageBase
, NvStorageSize
);
3736 Status
= GetFtwProtocol ((VOID
**)&FtwProtocol
);
3738 // If FTW protocol has been installed, no need to check FTW last write data hob.
3740 if (EFI_ERROR (Status
)) {
3742 // Check the FTW last write data hob.
3744 GuidHob
= GetFirstGuidHob (&gEdkiiFaultTolerantWriteGuid
);
3745 if (GuidHob
!= NULL
) {
3746 FtwLastWriteData
= (FAULT_TOLERANT_WRITE_LAST_WRITE_DATA
*) GET_GUID_HOB_DATA (GuidHob
);
3747 if (FtwLastWriteData
->TargetAddress
== NvStorageBase
) {
3748 DEBUG ((EFI_D_INFO
, "Variable: NV storage is backed up in spare block: 0x%x\n", (UINTN
) FtwLastWriteData
->SpareAddress
));
3750 // Copy the backed up NV storage data to the memory buffer from spare block.
3752 CopyMem (NvStorageData
, (UINT8
*) (UINTN
) (FtwLastWriteData
->SpareAddress
), NvStorageSize
);
3753 } else if ((FtwLastWriteData
->TargetAddress
> NvStorageBase
) &&
3754 (FtwLastWriteData
->TargetAddress
< (NvStorageBase
+ NvStorageSize
))) {
3756 // Flash NV storage from the Offset is backed up in spare block.
3758 BackUpOffset
= (UINT32
) (FtwLastWriteData
->TargetAddress
- NvStorageBase
);
3759 BackUpSize
= NvStorageSize
- BackUpOffset
;
3760 DEBUG ((EFI_D_INFO
, "Variable: High partial NV storage from offset: %x is backed up in spare block: 0x%x\n", BackUpOffset
, (UINTN
) FtwLastWriteData
->SpareAddress
));
3762 // Copy the partial backed up NV storage data to the memory buffer from spare block.
3764 CopyMem (NvStorageData
+ BackUpOffset
, (UINT8
*) (UINTN
) FtwLastWriteData
->SpareAddress
, BackUpSize
);
3769 FvHeader
= (EFI_FIRMWARE_VOLUME_HEADER
*) NvStorageData
;
3772 // Check if the Firmware Volume is not corrupted
3774 if ((FvHeader
->Signature
!= EFI_FVH_SIGNATURE
) || (!CompareGuid (&gEfiSystemNvDataFvGuid
, &FvHeader
->FileSystemGuid
))) {
3775 FreePool (NvStorageData
);
3776 DEBUG ((EFI_D_ERROR
, "Firmware Volume for Variable Store is corrupted\n"));
3777 return EFI_VOLUME_CORRUPTED
;
3780 VariableStoreBase
= (UINTN
) FvHeader
+ FvHeader
->HeaderLength
;
3781 VariableStoreLength
= NvStorageSize
- FvHeader
->HeaderLength
;
3783 mNvFvHeaderCache
= FvHeader
;
3784 mVariableModuleGlobal
->VariableGlobal
.NonVolatileVariableBase
= VariableStoreBase
;
3785 mNvVariableCache
= (VARIABLE_STORE_HEADER
*) (UINTN
) VariableStoreBase
;
3786 if (GetVariableStoreStatus (mNvVariableCache
) != EfiValid
) {
3787 FreePool (NvStorageData
);
3788 mNvFvHeaderCache
= NULL
;
3789 mNvVariableCache
= NULL
;
3790 DEBUG((EFI_D_ERROR
, "Variable Store header is corrupted\n"));
3791 return EFI_VOLUME_CORRUPTED
;
3793 ASSERT(mNvVariableCache
->Size
== VariableStoreLength
);
3795 ASSERT (sizeof (VARIABLE_STORE_HEADER
) <= VariableStoreLength
);
3797 mVariableModuleGlobal
->VariableGlobal
.AuthFormat
= (BOOLEAN
)(CompareGuid (&mNvVariableCache
->Signature
, &gEfiAuthenticatedVariableGuid
));
3799 HwErrStorageSize
= PcdGet32 (PcdHwErrStorageSize
);
3800 MaxUserNvVariableSpaceSize
= PcdGet32 (PcdMaxUserNvVariableSpaceSize
);
3801 BoottimeReservedNvVariableSpaceSize
= PcdGet32 (PcdBoottimeReservedNvVariableSpaceSize
);
3804 // Note that in EdkII variable driver implementation, Hardware Error Record type variable
3805 // is stored with common variable in the same NV region. So the platform integrator should
3806 // ensure that the value of PcdHwErrStorageSize is less than the value of
3807 // (VariableStoreLength - sizeof (VARIABLE_STORE_HEADER)).
3809 ASSERT (HwErrStorageSize
< (VariableStoreLength
- sizeof (VARIABLE_STORE_HEADER
)));
3811 // Ensure that the value of PcdMaxUserNvVariableSpaceSize is less than the value of
3812 // (VariableStoreLength - sizeof (VARIABLE_STORE_HEADER)) - PcdGet32 (PcdHwErrStorageSize).
3814 ASSERT (MaxUserNvVariableSpaceSize
< (VariableStoreLength
- sizeof (VARIABLE_STORE_HEADER
) - HwErrStorageSize
));
3816 // Ensure that the value of PcdBoottimeReservedNvVariableSpaceSize is less than the value of
3817 // (VariableStoreLength - sizeof (VARIABLE_STORE_HEADER)) - PcdGet32 (PcdHwErrStorageSize).
3819 ASSERT (BoottimeReservedNvVariableSpaceSize
< (VariableStoreLength
- sizeof (VARIABLE_STORE_HEADER
) - HwErrStorageSize
));
3821 mVariableModuleGlobal
->CommonVariableSpace
= ((UINTN
) VariableStoreLength
- sizeof (VARIABLE_STORE_HEADER
) - HwErrStorageSize
);
3822 mVariableModuleGlobal
->CommonMaxUserVariableSpace
= ((MaxUserNvVariableSpaceSize
!= 0) ? MaxUserNvVariableSpaceSize
: mVariableModuleGlobal
->CommonVariableSpace
);
3823 mVariableModuleGlobal
->CommonRuntimeVariableSpace
= mVariableModuleGlobal
->CommonVariableSpace
- BoottimeReservedNvVariableSpaceSize
;
3825 DEBUG ((EFI_D_INFO
, "Variable driver common space: 0x%x 0x%x 0x%x\n", mVariableModuleGlobal
->CommonVariableSpace
, mVariableModuleGlobal
->CommonMaxUserVariableSpace
, mVariableModuleGlobal
->CommonRuntimeVariableSpace
));
3828 // The max NV variable size should be < (VariableStoreLength - sizeof (VARIABLE_STORE_HEADER)).
3830 ASSERT (GetNonVolatileMaxVariableSize () < (VariableStoreLength
- sizeof (VARIABLE_STORE_HEADER
)));
3832 mVariableModuleGlobal
->MaxVariableSize
= PcdGet32 (PcdMaxVariableSize
);
3833 mVariableModuleGlobal
->MaxAuthVariableSize
= ((PcdGet32 (PcdMaxAuthVariableSize
) != 0) ? PcdGet32 (PcdMaxAuthVariableSize
) : mVariableModuleGlobal
->MaxVariableSize
);
3836 // Parse non-volatile variable data and get last variable offset.
3838 Variable
= GetStartPointer ((VARIABLE_STORE_HEADER
*)(UINTN
)VariableStoreBase
);
3839 while (IsValidVariableHeader (Variable
, GetEndPointer ((VARIABLE_STORE_HEADER
*)(UINTN
)VariableStoreBase
))) {
3840 NextVariable
= GetNextVariablePtr (Variable
);
3841 VariableSize
= (UINTN
) NextVariable
- (UINTN
) Variable
;
3842 if ((Variable
->Attributes
& (EFI_VARIABLE_NON_VOLATILE
| EFI_VARIABLE_HARDWARE_ERROR_RECORD
)) == (EFI_VARIABLE_NON_VOLATILE
| EFI_VARIABLE_HARDWARE_ERROR_RECORD
)) {
3843 mVariableModuleGlobal
->HwErrVariableTotalSize
+= VariableSize
;
3845 mVariableModuleGlobal
->CommonVariableTotalSize
+= VariableSize
;
3848 Variable
= NextVariable
;
3850 mVariableModuleGlobal
->NonVolatileLastVariableOffset
= (UINTN
) Variable
- (UINTN
) VariableStoreBase
;
3852 *NvFvHeader
= FvHeader
;
3857 Flush the HOB variable to flash.
3859 @param[in] VariableName Name of variable has been updated or deleted.
3860 @param[in] VendorGuid Guid of variable has been updated or deleted.
3864 FlushHobVariableToFlash (
3865 IN CHAR16
*VariableName
,
3866 IN EFI_GUID
*VendorGuid
3870 VARIABLE_STORE_HEADER
*VariableStoreHeader
;
3871 VARIABLE_HEADER
*Variable
;
3873 VARIABLE_POINTER_TRACK VariablePtrTrack
;
3879 // Flush the HOB variable to flash.
3881 if (mVariableModuleGlobal
->VariableGlobal
.HobVariableBase
!= 0) {
3882 VariableStoreHeader
= (VARIABLE_STORE_HEADER
*) (UINTN
) mVariableModuleGlobal
->VariableGlobal
.HobVariableBase
;
3884 // Set HobVariableBase to 0, it can avoid SetVariable to call back.
3886 mVariableModuleGlobal
->VariableGlobal
.HobVariableBase
= 0;
3887 for ( Variable
= GetStartPointer (VariableStoreHeader
)
3888 ; IsValidVariableHeader (Variable
, GetEndPointer (VariableStoreHeader
))
3889 ; Variable
= GetNextVariablePtr (Variable
)
3891 if (Variable
->State
!= VAR_ADDED
) {
3893 // The HOB variable has been set to DELETED state in local.
3897 ASSERT ((Variable
->Attributes
& EFI_VARIABLE_NON_VOLATILE
) != 0);
3898 if (VendorGuid
== NULL
|| VariableName
== NULL
||
3899 !CompareGuid (VendorGuid
, GetVendorGuidPtr (Variable
)) ||
3900 StrCmp (VariableName
, GetVariableNamePtr (Variable
)) != 0) {
3901 VariableData
= GetVariableDataPtr (Variable
);
3902 FindVariable (GetVariableNamePtr (Variable
), GetVendorGuidPtr (Variable
), &VariablePtrTrack
, &mVariableModuleGlobal
->VariableGlobal
, FALSE
);
3903 Status
= UpdateVariable (
3904 GetVariableNamePtr (Variable
),
3905 GetVendorGuidPtr (Variable
),
3907 DataSizeOfVariable (Variable
),
3908 Variable
->Attributes
,
3914 DEBUG ((EFI_D_INFO
, "Variable driver flush the HOB variable to flash: %g %s %r\n", GetVendorGuidPtr (Variable
), GetVariableNamePtr (Variable
), Status
));
3917 // The updated or deleted variable is matched with this HOB variable.
3918 // Don't break here because we will try to set other HOB variables
3919 // since this variable could be set successfully.
3921 Status
= EFI_SUCCESS
;
3923 if (!EFI_ERROR (Status
)) {
3925 // If set variable successful, or the updated or deleted variable is matched with the HOB variable,
3926 // set the HOB variable to DELETED state in local.
3928 DEBUG ((EFI_D_INFO
, "Variable driver set the HOB variable to DELETED state in local: %g %s\n", GetVendorGuidPtr (Variable
), GetVariableNamePtr (Variable
)));
3929 Variable
->State
&= VAR_DELETED
;
3936 // We still have HOB variable(s) not flushed in flash.
3938 mVariableModuleGlobal
->VariableGlobal
.HobVariableBase
= (EFI_PHYSICAL_ADDRESS
) (UINTN
) VariableStoreHeader
;
3941 // All HOB variables have been flushed in flash.
3943 DEBUG ((EFI_D_INFO
, "Variable driver: all HOB variables have been flushed in flash.\n"));
3944 if (!AtRuntime ()) {
3945 FreePool ((VOID
*) VariableStoreHeader
);
3953 Initializes variable write service after FTW was ready.
3955 @retval EFI_SUCCESS Function successfully executed.
3956 @retval Others Fail to initialize the variable service.
3960 VariableWriteServiceInitialize (
3967 EFI_PHYSICAL_ADDRESS VariableStoreBase
;
3968 EFI_PHYSICAL_ADDRESS NvStorageBase
;
3969 VARIABLE_ENTRY_PROPERTY
*VariableEntry
;
3971 AcquireLockOnlyAtBootTime(&mVariableModuleGlobal
->VariableGlobal
.VariableServicesLock
);
3973 NvStorageBase
= (EFI_PHYSICAL_ADDRESS
) PcdGet64 (PcdFlashNvStorageVariableBase64
);
3974 if (NvStorageBase
== 0) {
3975 NvStorageBase
= (EFI_PHYSICAL_ADDRESS
) PcdGet32 (PcdFlashNvStorageVariableBase
);
3977 VariableStoreBase
= NvStorageBase
+ (mNvFvHeaderCache
->HeaderLength
);
3980 // Let NonVolatileVariableBase point to flash variable store base directly after FTW ready.
3982 mVariableModuleGlobal
->VariableGlobal
.NonVolatileVariableBase
= VariableStoreBase
;
3985 // Check if the free area is really free.
3987 for (Index
= mVariableModuleGlobal
->NonVolatileLastVariableOffset
; Index
< mNvVariableCache
->Size
; Index
++) {
3988 Data
= ((UINT8
*) mNvVariableCache
)[Index
];
3991 // There must be something wrong in variable store, do reclaim operation.
3994 mVariableModuleGlobal
->VariableGlobal
.NonVolatileVariableBase
,
3995 &mVariableModuleGlobal
->NonVolatileLastVariableOffset
,
4001 if (EFI_ERROR (Status
)) {
4002 ReleaseLockOnlyAtBootTime (&mVariableModuleGlobal
->VariableGlobal
.VariableServicesLock
);
4009 FlushHobVariableToFlash (NULL
, NULL
);
4011 Status
= EFI_SUCCESS
;
4012 ZeroMem (&mAuthContextOut
, sizeof (mAuthContextOut
));
4013 if (mVariableModuleGlobal
->VariableGlobal
.AuthFormat
) {
4015 // Authenticated variable initialize.
4017 mAuthContextIn
.StructSize
= sizeof (AUTH_VAR_LIB_CONTEXT_IN
);
4018 mAuthContextIn
.MaxAuthVariableSize
= mVariableModuleGlobal
->MaxAuthVariableSize
- GetVariableHeaderSize ();
4019 Status
= AuthVariableLibInitialize (&mAuthContextIn
, &mAuthContextOut
);
4020 if (!EFI_ERROR (Status
)) {
4021 DEBUG ((EFI_D_INFO
, "Variable driver will work with auth variable support!\n"));
4022 mVariableModuleGlobal
->VariableGlobal
.AuthSupport
= TRUE
;
4023 if (mAuthContextOut
.AuthVarEntry
!= NULL
) {
4024 for (Index
= 0; Index
< mAuthContextOut
.AuthVarEntryCount
; Index
++) {
4025 VariableEntry
= &mAuthContextOut
.AuthVarEntry
[Index
];
4026 Status
= VarCheckLibVariablePropertySet (
4027 VariableEntry
->Name
,
4028 VariableEntry
->Guid
,
4029 &VariableEntry
->VariableProperty
4031 ASSERT_EFI_ERROR (Status
);
4034 } else if (Status
== EFI_UNSUPPORTED
) {
4035 DEBUG ((EFI_D_INFO
, "NOTICE - AuthVariableLibInitialize() returns %r!\n", Status
));
4036 DEBUG ((EFI_D_INFO
, "Variable driver will continue to work without auth variable support!\n"));
4037 mVariableModuleGlobal
->VariableGlobal
.AuthSupport
= FALSE
;
4038 Status
= EFI_SUCCESS
;
4042 if (!EFI_ERROR (Status
)) {
4043 for (Index
= 0; Index
< ARRAY_SIZE (mVariableEntryProperty
); Index
++) {
4044 VariableEntry
= &mVariableEntryProperty
[Index
];
4045 Status
= VarCheckLibVariablePropertySet (VariableEntry
->Name
, VariableEntry
->Guid
, &VariableEntry
->VariableProperty
);
4046 ASSERT_EFI_ERROR (Status
);
4050 ReleaseLockOnlyAtBootTime (&mVariableModuleGlobal
->VariableGlobal
.VariableServicesLock
);
4053 // Initialize MOR Lock variable.
4062 Initializes variable store area for non-volatile and volatile variable.
4064 @retval EFI_SUCCESS Function successfully executed.
4065 @retval EFI_OUT_OF_RESOURCES Fail to allocate enough memory resource.
4069 VariableCommonInitialize (
4074 VARIABLE_STORE_HEADER
*VolatileVariableStore
;
4075 VARIABLE_STORE_HEADER
*VariableStoreHeader
;
4076 UINT64 VariableStoreLength
;
4078 EFI_HOB_GUID_TYPE
*GuidHob
;
4079 EFI_GUID
*VariableGuid
;
4080 EFI_FIRMWARE_VOLUME_HEADER
*NvFvHeader
;
4083 // Allocate runtime memory for variable driver global structure.
4085 mVariableModuleGlobal
= AllocateRuntimeZeroPool (sizeof (VARIABLE_MODULE_GLOBAL
));
4086 if (mVariableModuleGlobal
== NULL
) {
4087 return EFI_OUT_OF_RESOURCES
;
4090 InitializeLock (&mVariableModuleGlobal
->VariableGlobal
.VariableServicesLock
, TPL_NOTIFY
);
4093 // Init non-volatile variable store.
4096 Status
= InitNonVolatileVariableStore (&NvFvHeader
);
4097 if (EFI_ERROR (Status
)) {
4098 FreePool (mVariableModuleGlobal
);
4103 // mVariableModuleGlobal->VariableGlobal.AuthFormat
4104 // has been initialized in InitNonVolatileVariableStore().
4106 if (mVariableModuleGlobal
->VariableGlobal
.AuthFormat
) {
4107 DEBUG ((EFI_D_INFO
, "Variable driver will work with auth variable format!\n"));
4109 // Set AuthSupport to FALSE first, VariableWriteServiceInitialize() will initialize it.
4111 mVariableModuleGlobal
->VariableGlobal
.AuthSupport
= FALSE
;
4112 VariableGuid
= &gEfiAuthenticatedVariableGuid
;
4114 DEBUG ((EFI_D_INFO
, "Variable driver will work without auth variable support!\n"));
4115 mVariableModuleGlobal
->VariableGlobal
.AuthSupport
= FALSE
;
4116 VariableGuid
= &gEfiVariableGuid
;
4120 // Get HOB variable store.
4122 GuidHob
= GetFirstGuidHob (VariableGuid
);
4123 if (GuidHob
!= NULL
) {
4124 VariableStoreHeader
= GET_GUID_HOB_DATA (GuidHob
);
4125 VariableStoreLength
= GuidHob
->Header
.HobLength
- sizeof (EFI_HOB_GUID_TYPE
);
4126 if (GetVariableStoreStatus (VariableStoreHeader
) == EfiValid
) {
4127 mVariableModuleGlobal
->VariableGlobal
.HobVariableBase
= (EFI_PHYSICAL_ADDRESS
) (UINTN
) AllocateRuntimeCopyPool ((UINTN
) VariableStoreLength
, (VOID
*) VariableStoreHeader
);
4128 if (mVariableModuleGlobal
->VariableGlobal
.HobVariableBase
== 0) {
4129 FreePool (NvFvHeader
);
4130 FreePool (mVariableModuleGlobal
);
4131 return EFI_OUT_OF_RESOURCES
;
4134 DEBUG ((EFI_D_ERROR
, "HOB Variable Store header is corrupted!\n"));
4139 // Allocate memory for volatile variable store, note that there is a scratch space to store scratch data.
4141 ScratchSize
= GetNonVolatileMaxVariableSize ();
4142 mVariableModuleGlobal
->ScratchBufferSize
= ScratchSize
;
4143 VolatileVariableStore
= AllocateRuntimePool (PcdGet32 (PcdVariableStoreSize
) + ScratchSize
);
4144 if (VolatileVariableStore
== NULL
) {
4145 if (mVariableModuleGlobal
->VariableGlobal
.HobVariableBase
!= 0) {
4146 FreePool ((VOID
*) (UINTN
) mVariableModuleGlobal
->VariableGlobal
.HobVariableBase
);
4148 FreePool (NvFvHeader
);
4149 FreePool (mVariableModuleGlobal
);
4150 return EFI_OUT_OF_RESOURCES
;
4153 SetMem (VolatileVariableStore
, PcdGet32 (PcdVariableStoreSize
) + ScratchSize
, 0xff);
4156 // Initialize Variable Specific Data.
4158 mVariableModuleGlobal
->VariableGlobal
.VolatileVariableBase
= (EFI_PHYSICAL_ADDRESS
) (UINTN
) VolatileVariableStore
;
4159 mVariableModuleGlobal
->VolatileLastVariableOffset
= (UINTN
) GetStartPointer (VolatileVariableStore
) - (UINTN
) VolatileVariableStore
;
4161 CopyGuid (&VolatileVariableStore
->Signature
, VariableGuid
);
4162 VolatileVariableStore
->Size
= PcdGet32 (PcdVariableStoreSize
);
4163 VolatileVariableStore
->Format
= VARIABLE_STORE_FORMATTED
;
4164 VolatileVariableStore
->State
= VARIABLE_STORE_HEALTHY
;
4165 VolatileVariableStore
->Reserved
= 0;
4166 VolatileVariableStore
->Reserved1
= 0;
4173 Get the proper fvb handle and/or fvb protocol by the given Flash address.
4175 @param[in] Address The Flash address.
4176 @param[out] FvbHandle In output, if it is not NULL, it points to the proper FVB handle.
4177 @param[out] FvbProtocol In output, if it is not NULL, it points to the proper FVB protocol.
4181 GetFvbInfoByAddress (
4182 IN EFI_PHYSICAL_ADDRESS Address
,
4183 OUT EFI_HANDLE
*FvbHandle OPTIONAL
,
4184 OUT EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
**FvbProtocol OPTIONAL
4188 EFI_HANDLE
*HandleBuffer
;
4191 EFI_PHYSICAL_ADDRESS FvbBaseAddress
;
4192 EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*Fvb
;
4193 EFI_FVB_ATTRIBUTES_2 Attributes
;
4195 UINTN NumberOfBlocks
;
4197 HandleBuffer
= NULL
;
4199 // Get all FVB handles.
4201 Status
= GetFvbCountAndBuffer (&HandleCount
, &HandleBuffer
);
4202 if (EFI_ERROR (Status
)) {
4203 return EFI_NOT_FOUND
;
4207 // Get the FVB to access variable store.
4210 for (Index
= 0; Index
< HandleCount
; Index
+= 1, Status
= EFI_NOT_FOUND
, Fvb
= NULL
) {
4211 Status
= GetFvbByHandle (HandleBuffer
[Index
], &Fvb
);
4212 if (EFI_ERROR (Status
)) {
4213 Status
= EFI_NOT_FOUND
;
4218 // Ensure this FVB protocol supported Write operation.
4220 Status
= Fvb
->GetAttributes (Fvb
, &Attributes
);
4221 if (EFI_ERROR (Status
) || ((Attributes
& EFI_FVB2_WRITE_STATUS
) == 0)) {
4226 // Compare the address and select the right one.
4228 Status
= Fvb
->GetPhysicalAddress (Fvb
, &FvbBaseAddress
);
4229 if (EFI_ERROR (Status
)) {
4234 // Assume one FVB has one type of BlockSize.
4236 Status
= Fvb
->GetBlockSize (Fvb
, 0, &BlockSize
, &NumberOfBlocks
);
4237 if (EFI_ERROR (Status
)) {
4241 if ((Address
>= FvbBaseAddress
) && (Address
< (FvbBaseAddress
+ BlockSize
* NumberOfBlocks
))) {
4242 if (FvbHandle
!= NULL
) {
4243 *FvbHandle
= HandleBuffer
[Index
];
4245 if (FvbProtocol
!= NULL
) {
4248 Status
= EFI_SUCCESS
;
4252 FreePool (HandleBuffer
);
4255 Status
= EFI_NOT_FOUND
;