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) 2009 - 2015, Intel Corporation. All rights reserved.<BR>
20 This program and the accompanying materials
21 are licensed and made available under the terms and conditions of the BSD License
22 which accompanies this distribution. The full text of the license may be found at
23 http://opensource.org/licenses/bsd-license.php
25 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
26 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
31 #include "AuthService.h"
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 /// The memory entry used for variable statistics data.
43 VARIABLE_INFO_ENTRY
*gVariableInfo
= NULL
;
46 /// The list to store the variables which cannot be set after the EFI_END_OF_DXE_EVENT_GROUP_GUID
47 /// or EVT_GROUP_READY_TO_BOOT event.
49 LIST_ENTRY mLockedVariableList
= INITIALIZE_LIST_HEAD_VARIABLE (mLockedVariableList
);
52 /// The flag to indicate whether the platform has left the DXE phase of execution.
54 BOOLEAN mEndOfDxe
= FALSE
;
57 /// The flag to indicate whether the variable storage locking is enabled.
59 BOOLEAN mEnableLocking
= TRUE
;
63 SecureBoot Hook for auth variable update.
65 @param[in] VariableName Name of Variable to be found.
66 @param[in] VendorGuid Variable vendor GUID.
71 IN CHAR16
*VariableName
,
72 IN EFI_GUID
*VendorGuid
76 Routine used to track statistical information about variable usage.
77 The data is stored in the EFI system table so it can be accessed later.
78 VariableInfo.efi can dump out the table. Only Boot Services variable
79 accesses are tracked by this code. The PcdVariableCollectStatistics
80 build flag controls if this feature is enabled.
82 A read that hits in the cache will have Read and Cache true for
83 the transaction. Data is allocated by this routine, but never
86 @param[in] VariableName Name of the Variable to track.
87 @param[in] VendorGuid Guid of the Variable to track.
88 @param[in] Volatile TRUE if volatile FALSE if non-volatile.
89 @param[in] Read TRUE if GetVariable() was called.
90 @param[in] Write TRUE if SetVariable() was called.
91 @param[in] Delete TRUE if deleted via SetVariable().
92 @param[in] Cache TRUE for a cache hit.
97 IN CHAR16
*VariableName
,
98 IN EFI_GUID
*VendorGuid
,
106 VARIABLE_INFO_ENTRY
*Entry
;
108 if (FeaturePcdGet (PcdVariableCollectStatistics
)) {
111 // Don't collect statistics at runtime.
115 if (gVariableInfo
== NULL
) {
117 // On the first call allocate a entry and place a pointer to it in
118 // the EFI System Table.
120 gVariableInfo
= AllocateZeroPool (sizeof (VARIABLE_INFO_ENTRY
));
121 ASSERT (gVariableInfo
!= NULL
);
123 CopyGuid (&gVariableInfo
->VendorGuid
, VendorGuid
);
124 gVariableInfo
->Name
= AllocatePool (StrSize (VariableName
));
125 ASSERT (gVariableInfo
->Name
!= NULL
);
126 StrCpy (gVariableInfo
->Name
, VariableName
);
127 gVariableInfo
->Volatile
= Volatile
;
131 for (Entry
= gVariableInfo
; Entry
!= NULL
; Entry
= Entry
->Next
) {
132 if (CompareGuid (VendorGuid
, &Entry
->VendorGuid
)) {
133 if (StrCmp (VariableName
, Entry
->Name
) == 0) {
141 Entry
->DeleteCount
++;
151 if (Entry
->Next
== NULL
) {
153 // If the entry is not in the table add it.
154 // Next iteration of the loop will fill in the data.
156 Entry
->Next
= AllocateZeroPool (sizeof (VARIABLE_INFO_ENTRY
));
157 ASSERT (Entry
->Next
!= NULL
);
159 CopyGuid (&Entry
->Next
->VendorGuid
, VendorGuid
);
160 Entry
->Next
->Name
= AllocatePool (StrSize (VariableName
));
161 ASSERT (Entry
->Next
->Name
!= NULL
);
162 StrCpy (Entry
->Next
->Name
, VariableName
);
163 Entry
->Next
->Volatile
= Volatile
;
173 This code checks if variable header is valid or not.
175 @param Variable Pointer to the Variable Header.
176 @param VariableStoreEnd Pointer to the Variable Store End.
178 @retval TRUE Variable header is valid.
179 @retval FALSE Variable header is not valid.
183 IsValidVariableHeader (
184 IN VARIABLE_HEADER
*Variable
,
185 IN VARIABLE_HEADER
*VariableStoreEnd
188 if ((Variable
== NULL
) || (Variable
>= VariableStoreEnd
) || (Variable
->StartId
!= VARIABLE_DATA
)) {
190 // Variable is NULL or has reached the end of variable store,
191 // or the StartId is not correct.
202 This function writes data to the FWH at the correct LBA even if the LBAs
205 @param Global Pointer to VARAIBLE_GLOBAL structure.
206 @param Volatile Point out the Variable is Volatile or Non-Volatile.
207 @param SetByIndex TRUE if target pointer is given as index.
208 FALSE if target pointer is absolute.
209 @param Fvb Pointer to the writable FVB protocol.
210 @param DataPtrIndex Pointer to the Data from the end of VARIABLE_STORE_HEADER
212 @param DataSize Size of data to be written.
213 @param Buffer Pointer to the buffer from which data is written.
215 @retval EFI_INVALID_PARAMETER Parameters not valid.
216 @retval EFI_SUCCESS Variable store successfully updated.
220 UpdateVariableStore (
221 IN VARIABLE_GLOBAL
*Global
,
223 IN BOOLEAN SetByIndex
,
224 IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*Fvb
,
225 IN UINTN DataPtrIndex
,
230 EFI_FV_BLOCK_MAP_ENTRY
*PtrBlockMapEntry
;
238 EFI_FIRMWARE_VOLUME_HEADER
*FwVolHeader
;
239 VARIABLE_STORE_HEADER
*VolatileBase
;
240 EFI_PHYSICAL_ADDRESS FvVolHdr
;
241 EFI_PHYSICAL_ADDRESS DataPtr
;
245 DataPtr
= DataPtrIndex
;
248 // Check if the Data is Volatile.
252 return EFI_INVALID_PARAMETER
;
254 Status
= Fvb
->GetPhysicalAddress(Fvb
, &FvVolHdr
);
255 ASSERT_EFI_ERROR (Status
);
257 FwVolHeader
= (EFI_FIRMWARE_VOLUME_HEADER
*) ((UINTN
) FvVolHdr
);
259 // Data Pointer should point to the actual Address where data is to be
263 DataPtr
+= mVariableModuleGlobal
->VariableGlobal
.NonVolatileVariableBase
;
266 if ((DataPtr
+ DataSize
) >= ((EFI_PHYSICAL_ADDRESS
) (UINTN
) ((UINT8
*) FwVolHeader
+ FwVolHeader
->FvLength
))) {
267 return EFI_INVALID_PARAMETER
;
271 // Data Pointer should point to the actual Address where data is to be
274 VolatileBase
= (VARIABLE_STORE_HEADER
*) ((UINTN
) mVariableModuleGlobal
->VariableGlobal
.VolatileVariableBase
);
276 DataPtr
+= mVariableModuleGlobal
->VariableGlobal
.VolatileVariableBase
;
279 if ((DataPtr
+ DataSize
) >= ((UINTN
) ((UINT8
*) VolatileBase
+ VolatileBase
->Size
))) {
280 return EFI_INVALID_PARAMETER
;
284 // If Volatile Variable just do a simple mem copy.
286 CopyMem ((UINT8
*)(UINTN
)DataPtr
, Buffer
, DataSize
);
291 // If we are here we are dealing with Non-Volatile Variables.
293 LinearOffset
= (UINTN
) FwVolHeader
;
294 CurrWritePtr
= (UINTN
) DataPtr
;
295 CurrWriteSize
= DataSize
;
299 if (CurrWritePtr
< LinearOffset
) {
300 return EFI_INVALID_PARAMETER
;
303 for (PtrBlockMapEntry
= FwVolHeader
->BlockMap
; PtrBlockMapEntry
->NumBlocks
!= 0; PtrBlockMapEntry
++) {
304 for (BlockIndex2
= 0; BlockIndex2
< PtrBlockMapEntry
->NumBlocks
; BlockIndex2
++) {
306 // Check to see if the Variable Writes are spanning through multiple
309 if ((CurrWritePtr
>= LinearOffset
) && (CurrWritePtr
< LinearOffset
+ PtrBlockMapEntry
->Length
)) {
310 if ((CurrWritePtr
+ CurrWriteSize
) <= (LinearOffset
+ PtrBlockMapEntry
->Length
)) {
311 Status
= Fvb
->Write (
314 (UINTN
) (CurrWritePtr
- LinearOffset
),
320 Size
= (UINT32
) (LinearOffset
+ PtrBlockMapEntry
->Length
- CurrWritePtr
);
321 Status
= Fvb
->Write (
324 (UINTN
) (CurrWritePtr
- LinearOffset
),
328 if (EFI_ERROR (Status
)) {
332 CurrWritePtr
= LinearOffset
+ PtrBlockMapEntry
->Length
;
333 CurrBuffer
= CurrBuffer
+ Size
;
334 CurrWriteSize
= CurrWriteSize
- Size
;
338 LinearOffset
+= PtrBlockMapEntry
->Length
;
349 This code gets the current status of Variable Store.
351 @param VarStoreHeader Pointer to the Variable Store Header.
353 @retval EfiRaw Variable store status is raw.
354 @retval EfiValid Variable store status is valid.
355 @retval EfiInvalid Variable store status is invalid.
358 VARIABLE_STORE_STATUS
359 GetVariableStoreStatus (
360 IN VARIABLE_STORE_HEADER
*VarStoreHeader
363 if (CompareGuid (&VarStoreHeader
->Signature
, &gEfiAuthenticatedVariableGuid
) &&
364 VarStoreHeader
->Format
== VARIABLE_STORE_FORMATTED
&&
365 VarStoreHeader
->State
== VARIABLE_STORE_HEALTHY
369 } else if (((UINT32
*)(&VarStoreHeader
->Signature
))[0] == 0xffffffff &&
370 ((UINT32
*)(&VarStoreHeader
->Signature
))[1] == 0xffffffff &&
371 ((UINT32
*)(&VarStoreHeader
->Signature
))[2] == 0xffffffff &&
372 ((UINT32
*)(&VarStoreHeader
->Signature
))[3] == 0xffffffff &&
373 VarStoreHeader
->Size
== 0xffffffff &&
374 VarStoreHeader
->Format
== 0xff &&
375 VarStoreHeader
->State
== 0xff
387 This code gets the size of name of variable.
389 @param Variable Pointer to the Variable Header.
391 @return UINTN Size of variable in bytes.
396 IN VARIABLE_HEADER
*Variable
399 if (Variable
->State
== (UINT8
) (-1) ||
400 Variable
->DataSize
== (UINT32
) (-1) ||
401 Variable
->NameSize
== (UINT32
) (-1) ||
402 Variable
->Attributes
== (UINT32
) (-1)) {
405 return (UINTN
) Variable
->NameSize
;
410 This code gets the size of variable data.
412 @param Variable Pointer to the Variable Header.
414 @return Size of variable in bytes.
419 IN VARIABLE_HEADER
*Variable
422 if (Variable
->State
== (UINT8
) (-1) ||
423 Variable
->DataSize
== (UINT32
) (-1) ||
424 Variable
->NameSize
== (UINT32
) (-1) ||
425 Variable
->Attributes
== (UINT32
) (-1)) {
428 return (UINTN
) Variable
->DataSize
;
433 This code gets the pointer to the variable name.
435 @param Variable Pointer to the Variable Header.
437 @return Pointer to Variable Name which is Unicode encoding.
442 IN VARIABLE_HEADER
*Variable
446 return (CHAR16
*) (Variable
+ 1);
451 This code gets the pointer to the variable data.
453 @param Variable Pointer to the Variable Header.
455 @return Pointer to Variable Data.
460 IN VARIABLE_HEADER
*Variable
466 // Be careful about pad size for alignment.
468 Value
= (UINTN
) GetVariableNamePtr (Variable
);
469 Value
+= NameSizeOfVariable (Variable
);
470 Value
+= GET_PAD_SIZE (NameSizeOfVariable (Variable
));
472 return (UINT8
*) Value
;
478 This code gets the pointer to the next variable header.
480 @param Variable Pointer to the Variable Header.
482 @return Pointer to next variable header.
487 IN VARIABLE_HEADER
*Variable
492 Value
= (UINTN
) GetVariableDataPtr (Variable
);
493 Value
+= DataSizeOfVariable (Variable
);
494 Value
+= GET_PAD_SIZE (DataSizeOfVariable (Variable
));
497 // Be careful about pad size for alignment.
499 return (VARIABLE_HEADER
*) HEADER_ALIGN (Value
);
504 Gets the pointer to the first variable header in given variable store area.
506 @param VarStoreHeader Pointer to the Variable Store Header.
508 @return Pointer to the first variable header.
513 IN VARIABLE_STORE_HEADER
*VarStoreHeader
517 // The end of variable store.
519 return (VARIABLE_HEADER
*) HEADER_ALIGN (VarStoreHeader
+ 1);
524 Gets the pointer to the end of the variable storage area.
526 This function gets pointer to the end of the variable storage
527 area, according to the input variable store header.
529 @param VarStoreHeader Pointer to the Variable Store Header.
531 @return Pointer to the end of the variable storage area.
536 IN VARIABLE_STORE_HEADER
*VarStoreHeader
540 // The end of variable store
542 return (VARIABLE_HEADER
*) HEADER_ALIGN ((UINTN
) VarStoreHeader
+ VarStoreHeader
->Size
);
546 Record variable error flag.
548 @param[in] Flag Variable error flag to record.
549 @param[in] VariableName Name of variable.
550 @param[in] VendorGuid Guid of variable.
551 @param[in] Attributes Attributes of the variable.
552 @param[in] VariableSize Size of the variable.
557 IN VAR_ERROR_FLAG Flag
,
558 IN CHAR16
*VariableName
,
559 IN EFI_GUID
*VendorGuid
,
560 IN UINT32 Attributes
,
561 IN UINTN VariableSize
565 VARIABLE_POINTER_TRACK Variable
;
566 VAR_ERROR_FLAG
*VarErrFlag
;
567 VAR_ERROR_FLAG TempFlag
;
570 DEBUG ((EFI_D_ERROR
, "RecordVarErrorFlag (0x%02x) %s:%g - 0x%08x - 0x%x\n", Flag
, VariableName
, VendorGuid
, Attributes
, VariableSize
));
571 if (Flag
== VAR_ERROR_FLAG_SYSTEM_ERROR
) {
573 DEBUG ((EFI_D_ERROR
, "CommonRuntimeVariableSpace = 0x%x - CommonVariableTotalSize = 0x%x\n", mVariableModuleGlobal
->CommonRuntimeVariableSpace
, mVariableModuleGlobal
->CommonVariableTotalSize
));
575 DEBUG ((EFI_D_ERROR
, "CommonVariableSpace = 0x%x - CommonVariableTotalSize = 0x%x\n", mVariableModuleGlobal
->CommonVariableSpace
, mVariableModuleGlobal
->CommonVariableTotalSize
));
578 DEBUG ((EFI_D_ERROR
, "CommonMaxUserVariableSpace = 0x%x - CommonUserVariableTotalSize = 0x%x\n", mVariableModuleGlobal
->CommonMaxUserVariableSpace
, mVariableModuleGlobal
->CommonUserVariableTotalSize
));
583 // Record error flag (it should have be initialized).
585 Status
= FindVariable (
587 &gEdkiiVarErrorFlagGuid
,
589 &mVariableModuleGlobal
->VariableGlobal
,
592 if (!EFI_ERROR (Status
)) {
593 VarErrFlag
= (VAR_ERROR_FLAG
*) GetVariableDataPtr (Variable
.CurrPtr
);
594 TempFlag
= *VarErrFlag
;
596 if (TempFlag
== *VarErrFlag
) {
599 Status
= UpdateVariableStore (
600 &mVariableModuleGlobal
->VariableGlobal
,
603 mVariableModuleGlobal
->FvbInstance
,
604 (UINTN
) VarErrFlag
- (UINTN
) mNvVariableCache
+ (UINTN
) mVariableModuleGlobal
->VariableGlobal
.NonVolatileVariableBase
,
608 if (!EFI_ERROR (Status
)) {
610 // Update the data in NV cache.
618 Initialize variable error flag.
620 Before EndOfDxe, the variable indicates the last boot variable error flag,
621 then it means the last boot variable error flag must be got before EndOfDxe.
622 After EndOfDxe, the variable indicates the current boot variable error flag,
623 then it means the current boot variable error flag must be got after EndOfDxe.
627 InitializeVarErrorFlag (
632 VARIABLE_POINTER_TRACK Variable
;
634 VAR_ERROR_FLAG VarErrFlag
;
640 Flag
= VAR_ERROR_FLAG_NO_ERROR
;
641 DEBUG ((EFI_D_INFO
, "Initialize variable error flag (%02x)\n", Flag
));
643 Status
= FindVariable (
645 &gEdkiiVarErrorFlagGuid
,
647 &mVariableModuleGlobal
->VariableGlobal
,
650 if (!EFI_ERROR (Status
)) {
651 VarErrFlag
= *((VAR_ERROR_FLAG
*) GetVariableDataPtr (Variable
.CurrPtr
));
652 if (VarErrFlag
== Flag
) {
659 &gEdkiiVarErrorFlagGuid
,
662 VARIABLE_ATTRIBUTE_NV_BS_RT
,
673 @param[in] Variable Pointer to variable header.
675 @retval TRUE User variable.
676 @retval FALSE System variable.
681 IN VARIABLE_HEADER
*Variable
684 VAR_CHECK_VARIABLE_PROPERTY Property
;
687 // Only after End Of Dxe, the variables belong to system variable are fixed.
688 // If PcdMaxUserNvStorageVariableSize is 0, it means user variable share the same NV storage with system variable,
689 // then no need to check if the variable is user variable or not specially.
691 if (mEndOfDxe
&& (mVariableModuleGlobal
->CommonMaxUserVariableSpace
!= mVariableModuleGlobal
->CommonVariableSpace
)) {
692 if (InternalVarCheckVariablePropertyGet (GetVariableNamePtr (Variable
), &Variable
->VendorGuid
, &Property
) == EFI_NOT_FOUND
) {
700 Calculate common user variable total size.
704 CalculateCommonUserVariableTotalSize (
708 VARIABLE_HEADER
*Variable
;
709 VARIABLE_HEADER
*NextVariable
;
711 VAR_CHECK_VARIABLE_PROPERTY Property
;
714 // Only after End Of Dxe, the variables belong to system variable are fixed.
715 // If PcdMaxUserNvStorageVariableSize is 0, it means user variable share the same NV storage with system variable,
716 // then no need to calculate the common user variable total size specially.
718 if (mEndOfDxe
&& (mVariableModuleGlobal
->CommonMaxUserVariableSpace
!= mVariableModuleGlobal
->CommonVariableSpace
)) {
719 Variable
= GetStartPointer (mNvVariableCache
);
720 while (IsValidVariableHeader (Variable
, GetEndPointer (mNvVariableCache
))) {
721 NextVariable
= GetNextVariablePtr (Variable
);
722 VariableSize
= (UINTN
) NextVariable
- (UINTN
) Variable
;
723 if ((Variable
->Attributes
& EFI_VARIABLE_HARDWARE_ERROR_RECORD
) != EFI_VARIABLE_HARDWARE_ERROR_RECORD
) {
724 if (InternalVarCheckVariablePropertyGet (GetVariableNamePtr (Variable
), &Variable
->VendorGuid
, &Property
) == EFI_NOT_FOUND
) {
726 // No property, it is user variable.
728 mVariableModuleGlobal
->CommonUserVariableTotalSize
+= VariableSize
;
732 Variable
= NextVariable
;
738 Initialize variable quota.
742 InitializeVariableQuota (
746 STATIC BOOLEAN Initialized
;
748 if (!mEndOfDxe
|| Initialized
) {
753 InitializeVarErrorFlag ();
754 CalculateCommonUserVariableTotalSize ();
759 Check the PubKeyIndex is a valid key or not.
761 This function will iterate the NV storage to see if this PubKeyIndex is still referenced
762 by any valid count-based auth variabe.
764 @param[in] PubKeyIndex Index of the public key in public key store.
766 @retval TRUE The PubKeyIndex is still in use.
767 @retval FALSE The PubKeyIndex is not referenced by any count-based auth variabe.
772 IN UINT32 PubKeyIndex
775 VARIABLE_HEADER
*Variable
;
776 VARIABLE_HEADER
*VariableStoreEnd
;
778 if (PubKeyIndex
> mPubKeyNumber
) {
782 Variable
= GetStartPointer ((VARIABLE_STORE_HEADER
*) (UINTN
) mVariableModuleGlobal
->VariableGlobal
.NonVolatileVariableBase
);
783 VariableStoreEnd
= GetEndPointer ((VARIABLE_STORE_HEADER
*) (UINTN
) mVariableModuleGlobal
->VariableGlobal
.NonVolatileVariableBase
);
785 while (IsValidVariableHeader (Variable
, VariableStoreEnd
)) {
786 if ((Variable
->State
== VAR_ADDED
|| Variable
->State
== (VAR_IN_DELETED_TRANSITION
& VAR_ADDED
)) &&
787 Variable
->PubKeyIndex
== PubKeyIndex
) {
790 Variable
= GetNextVariablePtr (Variable
);
798 Get the number of valid public key in PubKeyStore.
800 @param[in] PubKeyNumber Number of the public key in public key store.
802 @return Number of valid public key in PubKeyStore.
806 GetValidPubKeyNumber (
807 IN UINT32 PubKeyNumber
815 for (PubKeyIndex
= 1; PubKeyIndex
<= PubKeyNumber
; PubKeyIndex
++) {
816 if (IsValidPubKeyIndex (PubKeyIndex
)) {
826 Filter the useless key in public key store.
828 This function will find out all valid public keys in public key database, save them in new allocated
829 buffer NewPubKeyStore, and give the new PubKeyIndex. The caller is responsible for freeing buffer
830 NewPubKeyIndex and NewPubKeyStore with FreePool().
832 @param[in] PubKeyStore Point to the public key database.
833 @param[in] PubKeyNumber Number of the public key in PubKeyStore.
834 @param[out] NewPubKeyIndex Point to an array of new PubKeyIndex corresponds to NewPubKeyStore.
835 @param[out] NewPubKeyStore Saved all valid public keys in PubKeyStore.
836 @param[out] NewPubKeySize Buffer size of the NewPubKeyStore.
838 @retval EFI_SUCCESS Trim operation is complete successfully.
839 @retval EFI_OUT_OF_RESOURCES No enough memory resources, or no useless key in PubKeyStore.
844 IN UINT8
*PubKeyStore
,
845 IN UINT32 PubKeyNumber
,
846 OUT UINT32
**NewPubKeyIndex
,
847 OUT UINT8
**NewPubKeyStore
,
848 OUT UINT32
*NewPubKeySize
853 UINT32 NewPubKeyNumber
;
855 NewPubKeyNumber
= GetValidPubKeyNumber (PubKeyNumber
);
856 if (NewPubKeyNumber
== PubKeyNumber
) {
857 return EFI_OUT_OF_RESOURCES
;
860 if (NewPubKeyNumber
!= 0) {
861 *NewPubKeySize
= NewPubKeyNumber
* EFI_CERT_TYPE_RSA2048_SIZE
;
863 *NewPubKeySize
= sizeof (UINT8
);
866 *NewPubKeyStore
= AllocatePool (*NewPubKeySize
);
867 if (*NewPubKeyStore
== NULL
) {
868 return EFI_OUT_OF_RESOURCES
;
871 *NewPubKeyIndex
= AllocateZeroPool ((PubKeyNumber
+ 1) * sizeof (UINT32
));
872 if (*NewPubKeyIndex
== NULL
) {
873 FreePool (*NewPubKeyStore
);
874 *NewPubKeyStore
= NULL
;
875 return EFI_OUT_OF_RESOURCES
;
879 for (PubKeyIndex
= 1; PubKeyIndex
<= PubKeyNumber
; PubKeyIndex
++) {
880 if (IsValidPubKeyIndex (PubKeyIndex
)) {
882 *NewPubKeyStore
+ CopiedKey
* EFI_CERT_TYPE_RSA2048_SIZE
,
883 PubKeyStore
+ (PubKeyIndex
- 1) * EFI_CERT_TYPE_RSA2048_SIZE
,
884 EFI_CERT_TYPE_RSA2048_SIZE
886 (*NewPubKeyIndex
)[PubKeyIndex
] = ++CopiedKey
;
894 Variable store garbage collection and reclaim operation.
896 If ReclaimPubKeyStore is FALSE, reclaim variable space by deleting the obsoleted varaibles.
897 If ReclaimPubKeyStore is TRUE, reclaim invalid key in public key database and update the PubKeyIndex
898 for all the count-based authenticate variable in NV storage.
900 @param[in] VariableBase Base address of variable store.
901 @param[out] LastVariableOffset Offset of last variable.
902 @param[in] IsVolatile The variable store is volatile or not;
903 if it is non-volatile, need FTW.
904 @param[in, out] UpdatingPtrTrack Pointer to updating variable pointer track structure.
905 @param[in] NewVariable Pointer to new variable.
906 @param[in] NewVariableSize New variable size.
907 @param[in] ReclaimPubKeyStore Reclaim for public key database or not.
909 @return EFI_SUCCESS Reclaim operation has finished successfully.
910 @return EFI_OUT_OF_RESOURCES No enough memory resources or variable space.
911 @return EFI_DEVICE_ERROR The public key database doesn't exist.
912 @return Others Unexpect error happened during reclaim operation.
917 IN EFI_PHYSICAL_ADDRESS VariableBase
,
918 OUT UINTN
*LastVariableOffset
,
919 IN BOOLEAN IsVolatile
,
920 IN OUT VARIABLE_POINTER_TRACK
*UpdatingPtrTrack
,
921 IN VARIABLE_HEADER
*NewVariable
,
922 IN UINTN NewVariableSize
,
923 IN BOOLEAN ReclaimPubKeyStore
926 VARIABLE_HEADER
*Variable
;
927 VARIABLE_HEADER
*AddedVariable
;
928 VARIABLE_HEADER
*NextVariable
;
929 VARIABLE_HEADER
*NextAddedVariable
;
930 VARIABLE_STORE_HEADER
*VariableStoreHeader
;
932 UINTN MaximumBufferSize
;
940 UINTN CommonVariableTotalSize
;
941 UINTN CommonUserVariableTotalSize
;
942 UINTN HwErrVariableTotalSize
;
943 UINT32
*NewPubKeyIndex
;
944 UINT8
*NewPubKeyStore
;
945 UINT32 NewPubKeySize
;
946 VARIABLE_HEADER
*PubKeyHeader
;
947 VARIABLE_HEADER
*UpdatingVariable
;
948 VARIABLE_HEADER
*UpdatingInDeletedTransition
;
950 UpdatingVariable
= NULL
;
951 UpdatingInDeletedTransition
= NULL
;
952 if (UpdatingPtrTrack
!= NULL
) {
953 UpdatingVariable
= UpdatingPtrTrack
->CurrPtr
;
954 UpdatingInDeletedTransition
= UpdatingPtrTrack
->InDeletedTransitionPtr
;
957 VariableStoreHeader
= (VARIABLE_STORE_HEADER
*) ((UINTN
) VariableBase
);
959 CommonVariableTotalSize
= 0;
960 CommonUserVariableTotalSize
= 0;
961 HwErrVariableTotalSize
= 0;
962 NewPubKeyIndex
= NULL
;
963 NewPubKeyStore
= NULL
;
969 // Start Pointers for the variable.
971 Variable
= GetStartPointer (VariableStoreHeader
);
972 MaximumBufferSize
= sizeof (VARIABLE_STORE_HEADER
);
974 while (IsValidVariableHeader (Variable
, GetEndPointer (VariableStoreHeader
))) {
975 NextVariable
= GetNextVariablePtr (Variable
);
976 if ((Variable
->State
== VAR_ADDED
|| Variable
->State
== (VAR_IN_DELETED_TRANSITION
& VAR_ADDED
)) &&
977 Variable
!= UpdatingVariable
&&
978 Variable
!= UpdatingInDeletedTransition
980 VariableSize
= (UINTN
) NextVariable
- (UINTN
) Variable
;
981 MaximumBufferSize
+= VariableSize
;
984 Variable
= NextVariable
;
987 if (NewVariable
!= NULL
) {
989 // Add the new variable size.
991 MaximumBufferSize
+= NewVariableSize
;
995 // Reserve the 1 Bytes with Oxff to identify the
996 // end of the variable buffer.
998 MaximumBufferSize
+= 1;
999 ValidBuffer
= AllocatePool (MaximumBufferSize
);
1000 if (ValidBuffer
== NULL
) {
1001 return EFI_OUT_OF_RESOURCES
;
1005 // For NV variable reclaim, don't allocate pool here and just use mNvVariableCache
1006 // as the buffer to reduce SMRAM consumption for SMM variable driver.
1008 MaximumBufferSize
= mNvVariableCache
->Size
;
1009 ValidBuffer
= (UINT8
*) mNvVariableCache
;
1012 SetMem (ValidBuffer
, MaximumBufferSize
, 0xff);
1015 // Copy variable store header.
1017 CopyMem (ValidBuffer
, VariableStoreHeader
, sizeof (VARIABLE_STORE_HEADER
));
1018 CurrPtr
= (UINT8
*) GetStartPointer ((VARIABLE_STORE_HEADER
*) ValidBuffer
);
1020 if (ReclaimPubKeyStore
) {
1021 ASSERT (IsVolatile
== FALSE
);
1023 // Trim the PubKeyStore and get new PubKeyIndex.
1025 Status
= PubKeyStoreFilter (
1032 if (EFI_ERROR (Status
)) {
1035 ASSERT ((NewPubKeyIndex
!= NULL
) && (NewPubKeyStore
!= NULL
));
1038 // Refresh the PubKeyIndex for all valid variables (ADDED and IN_DELETED_TRANSITION).
1040 Variable
= GetStartPointer (VariableStoreHeader
);
1041 while (IsValidVariableHeader (Variable
, GetEndPointer (VariableStoreHeader
))) {
1042 NextVariable
= GetNextVariablePtr (Variable
);
1043 if (Variable
->State
== VAR_ADDED
|| Variable
->State
== (VAR_IN_DELETED_TRANSITION
& VAR_ADDED
)) {
1044 if ((StrCmp (GetVariableNamePtr (Variable
), AUTHVAR_KEYDB_NAME
) == 0) &&
1045 (CompareGuid (&Variable
->VendorGuid
, &gEfiAuthenticatedVariableGuid
))) {
1047 // Skip the public key database, it will be reinstalled later.
1049 PubKeyHeader
= Variable
;
1050 Variable
= NextVariable
;
1054 VariableSize
= (UINTN
) NextVariable
- (UINTN
) Variable
;
1055 CopyMem (CurrPtr
, (UINT8
*) Variable
, VariableSize
);
1056 ((VARIABLE_HEADER
*) CurrPtr
)->PubKeyIndex
= NewPubKeyIndex
[Variable
->PubKeyIndex
];
1057 CurrPtr
+= VariableSize
;
1058 if ((Variable
->Attributes
& EFI_VARIABLE_HARDWARE_ERROR_RECORD
) == EFI_VARIABLE_HARDWARE_ERROR_RECORD
) {
1059 HwErrVariableTotalSize
+= VariableSize
;
1060 } else if ((Variable
->Attributes
& EFI_VARIABLE_HARDWARE_ERROR_RECORD
) != EFI_VARIABLE_HARDWARE_ERROR_RECORD
) {
1061 CommonVariableTotalSize
+= VariableSize
;
1062 if (IsUserVariable (Variable
)) {
1063 CommonUserVariableTotalSize
+= VariableSize
;
1067 Variable
= NextVariable
;
1071 // Reinstall the new public key database.
1073 ASSERT (PubKeyHeader
!= NULL
);
1074 if (PubKeyHeader
== NULL
) {
1075 Status
= EFI_DEVICE_ERROR
;
1078 CopyMem (CurrPtr
, (UINT8
*) PubKeyHeader
, sizeof (VARIABLE_HEADER
));
1079 Variable
= (VARIABLE_HEADER
*) CurrPtr
;
1080 Variable
->DataSize
= NewPubKeySize
;
1081 StrCpy (GetVariableNamePtr (Variable
), GetVariableNamePtr (PubKeyHeader
));
1082 CopyMem (GetVariableDataPtr (Variable
), NewPubKeyStore
, NewPubKeySize
);
1083 CurrPtr
= (UINT8
*) GetNextVariablePtr (Variable
);
1084 CommonVariableTotalSize
+= (UINTN
) CurrPtr
- (UINTN
) Variable
;
1085 if (IsUserVariable (Variable
)) {
1086 CommonUserVariableTotalSize
+= (UINTN
) CurrPtr
- (UINTN
) Variable
;
1090 // Reinstall all ADDED variables as long as they are not identical to Updating Variable.
1092 Variable
= GetStartPointer (VariableStoreHeader
);
1093 while (IsValidVariableHeader (Variable
, GetEndPointer (VariableStoreHeader
))) {
1094 NextVariable
= GetNextVariablePtr (Variable
);
1095 if (Variable
!= UpdatingVariable
&& Variable
->State
== VAR_ADDED
) {
1096 VariableSize
= (UINTN
) NextVariable
- (UINTN
) Variable
;
1097 CopyMem (CurrPtr
, (UINT8
*) Variable
, VariableSize
);
1098 CurrPtr
+= VariableSize
;
1099 if ((!IsVolatile
) && ((Variable
->Attributes
& EFI_VARIABLE_HARDWARE_ERROR_RECORD
) == EFI_VARIABLE_HARDWARE_ERROR_RECORD
)) {
1100 HwErrVariableTotalSize
+= VariableSize
;
1101 } else if ((!IsVolatile
) && ((Variable
->Attributes
& EFI_VARIABLE_HARDWARE_ERROR_RECORD
) != EFI_VARIABLE_HARDWARE_ERROR_RECORD
)) {
1102 CommonVariableTotalSize
+= VariableSize
;
1103 if (IsUserVariable (Variable
)) {
1104 CommonUserVariableTotalSize
+= VariableSize
;
1108 Variable
= NextVariable
;
1112 // Reinstall all in delete transition variables.
1114 Variable
= GetStartPointer (VariableStoreHeader
);
1115 while (IsValidVariableHeader (Variable
, GetEndPointer (VariableStoreHeader
))) {
1116 NextVariable
= GetNextVariablePtr (Variable
);
1117 if (Variable
!= UpdatingVariable
&& Variable
!= UpdatingInDeletedTransition
&& Variable
->State
== (VAR_IN_DELETED_TRANSITION
& VAR_ADDED
)) {
1120 // Buffer has cached all ADDED variable.
1121 // Per IN_DELETED variable, we have to guarantee that
1122 // no ADDED one in previous buffer.
1126 AddedVariable
= GetStartPointer ((VARIABLE_STORE_HEADER
*) ValidBuffer
);
1127 while (IsValidVariableHeader (AddedVariable
, GetEndPointer ((VARIABLE_STORE_HEADER
*) ValidBuffer
))) {
1128 NextAddedVariable
= GetNextVariablePtr (AddedVariable
);
1129 NameSize
= NameSizeOfVariable (AddedVariable
);
1130 if (CompareGuid (&AddedVariable
->VendorGuid
, &Variable
->VendorGuid
) &&
1131 NameSize
== NameSizeOfVariable (Variable
)
1133 Point0
= (VOID
*) GetVariableNamePtr (AddedVariable
);
1134 Point1
= (VOID
*) GetVariableNamePtr (Variable
);
1135 if (CompareMem (Point0
, Point1
, NameSize
) == 0) {
1140 AddedVariable
= NextAddedVariable
;
1144 // Promote VAR_IN_DELETED_TRANSITION to VAR_ADDED.
1146 VariableSize
= (UINTN
) NextVariable
- (UINTN
) Variable
;
1147 CopyMem (CurrPtr
, (UINT8
*) Variable
, VariableSize
);
1148 ((VARIABLE_HEADER
*) CurrPtr
)->State
= VAR_ADDED
;
1149 CurrPtr
+= VariableSize
;
1150 if ((!IsVolatile
) && ((Variable
->Attributes
& EFI_VARIABLE_HARDWARE_ERROR_RECORD
) == EFI_VARIABLE_HARDWARE_ERROR_RECORD
)) {
1151 HwErrVariableTotalSize
+= VariableSize
;
1152 } else if ((!IsVolatile
) && ((Variable
->Attributes
& EFI_VARIABLE_HARDWARE_ERROR_RECORD
) != EFI_VARIABLE_HARDWARE_ERROR_RECORD
)) {
1153 CommonVariableTotalSize
+= VariableSize
;
1154 if (IsUserVariable (Variable
)) {
1155 CommonUserVariableTotalSize
+= VariableSize
;
1161 Variable
= NextVariable
;
1165 // Install the new variable if it is not NULL.
1167 if (NewVariable
!= NULL
) {
1168 if ((UINTN
) (CurrPtr
- ValidBuffer
) + NewVariableSize
> VariableStoreHeader
->Size
) {
1170 // No enough space to store the new variable.
1172 Status
= EFI_OUT_OF_RESOURCES
;
1176 if ((NewVariable
->Attributes
& EFI_VARIABLE_HARDWARE_ERROR_RECORD
) == EFI_VARIABLE_HARDWARE_ERROR_RECORD
) {
1177 HwErrVariableTotalSize
+= NewVariableSize
;
1178 } else if ((NewVariable
->Attributes
& EFI_VARIABLE_HARDWARE_ERROR_RECORD
) != EFI_VARIABLE_HARDWARE_ERROR_RECORD
) {
1179 CommonVariableTotalSize
+= NewVariableSize
;
1180 if (IsUserVariable (NewVariable
)) {
1181 CommonUserVariableTotalSize
+= NewVariableSize
;
1184 if ((HwErrVariableTotalSize
> PcdGet32 (PcdHwErrStorageSize
)) ||
1185 (CommonVariableTotalSize
> mVariableModuleGlobal
->CommonVariableSpace
) ||
1186 (CommonUserVariableTotalSize
> mVariableModuleGlobal
->CommonMaxUserVariableSpace
)) {
1188 // No enough space to store the new variable by NV or NV+HR attribute.
1190 Status
= EFI_OUT_OF_RESOURCES
;
1195 CopyMem (CurrPtr
, (UINT8
*) NewVariable
, NewVariableSize
);
1196 ((VARIABLE_HEADER
*) CurrPtr
)->State
= VAR_ADDED
;
1197 if (UpdatingVariable
!= NULL
) {
1198 UpdatingPtrTrack
->CurrPtr
= (VARIABLE_HEADER
*)((UINTN
)UpdatingPtrTrack
->StartPtr
+ ((UINTN
)CurrPtr
- (UINTN
)GetStartPointer ((VARIABLE_STORE_HEADER
*) ValidBuffer
)));
1199 UpdatingPtrTrack
->InDeletedTransitionPtr
= NULL
;
1201 CurrPtr
+= NewVariableSize
;
1207 // If volatile variable store, just copy valid buffer.
1209 SetMem ((UINT8
*) (UINTN
) VariableBase
, VariableStoreHeader
->Size
, 0xff);
1210 CopyMem ((UINT8
*) (UINTN
) VariableBase
, ValidBuffer
, (UINTN
) (CurrPtr
- ValidBuffer
));
1211 *LastVariableOffset
= (UINTN
) (CurrPtr
- ValidBuffer
);
1212 Status
= EFI_SUCCESS
;
1215 // If non-volatile variable store, perform FTW here.
1217 Status
= FtwVariableSpace (
1219 (VARIABLE_STORE_HEADER
*) ValidBuffer
1221 if (!EFI_ERROR (Status
)) {
1222 *LastVariableOffset
= (UINTN
) (CurrPtr
- ValidBuffer
);
1223 mVariableModuleGlobal
->HwErrVariableTotalSize
= HwErrVariableTotalSize
;
1224 mVariableModuleGlobal
->CommonVariableTotalSize
= CommonVariableTotalSize
;
1225 mVariableModuleGlobal
->CommonUserVariableTotalSize
= CommonUserVariableTotalSize
;
1227 Variable
= GetStartPointer ((VARIABLE_STORE_HEADER
*)(UINTN
)VariableBase
);
1228 while (IsValidVariableHeader (Variable
, GetEndPointer ((VARIABLE_STORE_HEADER
*)(UINTN
)VariableBase
))) {
1229 NextVariable
= GetNextVariablePtr (Variable
);
1230 VariableSize
= (UINTN
) NextVariable
- (UINTN
) Variable
;
1231 if ((Variable
->Attributes
& EFI_VARIABLE_HARDWARE_ERROR_RECORD
) == EFI_VARIABLE_HARDWARE_ERROR_RECORD
) {
1232 mVariableModuleGlobal
->HwErrVariableTotalSize
+= VariableSize
;
1233 } else if ((Variable
->Attributes
& EFI_VARIABLE_HARDWARE_ERROR_RECORD
) != EFI_VARIABLE_HARDWARE_ERROR_RECORD
) {
1234 mVariableModuleGlobal
->CommonVariableTotalSize
+= VariableSize
;
1235 if (IsUserVariable (Variable
)) {
1236 mVariableModuleGlobal
->CommonUserVariableTotalSize
+= VariableSize
;
1240 Variable
= NextVariable
;
1242 *LastVariableOffset
= (UINTN
) Variable
- (UINTN
) VariableBase
;
1248 FreePool (ValidBuffer
);
1251 // For NV variable reclaim, we use mNvVariableCache as the buffer, so copy the data back.
1253 CopyMem (mNvVariableCache
, (UINT8
*)(UINTN
)VariableBase
, VariableStoreHeader
->Size
);
1255 if (NewPubKeyStore
!= NULL
) {
1256 FreePool (NewPubKeyStore
);
1259 if (NewPubKeyIndex
!= NULL
) {
1260 FreePool (NewPubKeyIndex
);
1268 Find the variable in the specified variable store.
1270 @param[in] VariableName Name of the variable to be found
1271 @param[in] VendorGuid Vendor GUID to be found.
1272 @param[in] IgnoreRtCheck Ignore EFI_VARIABLE_RUNTIME_ACCESS attribute
1273 check at runtime when searching variable.
1274 @param[in, out] PtrTrack Variable Track Pointer structure that contains Variable Information.
1276 @retval EFI_SUCCESS Variable found successfully
1277 @retval EFI_NOT_FOUND Variable not found
1281 IN CHAR16
*VariableName
,
1282 IN EFI_GUID
*VendorGuid
,
1283 IN BOOLEAN IgnoreRtCheck
,
1284 IN OUT VARIABLE_POINTER_TRACK
*PtrTrack
1287 VARIABLE_HEADER
*InDeletedVariable
;
1290 PtrTrack
->InDeletedTransitionPtr
= NULL
;
1293 // Find the variable by walk through HOB, volatile and non-volatile variable store.
1295 InDeletedVariable
= NULL
;
1297 for ( PtrTrack
->CurrPtr
= PtrTrack
->StartPtr
1298 ; IsValidVariableHeader (PtrTrack
->CurrPtr
, PtrTrack
->EndPtr
)
1299 ; PtrTrack
->CurrPtr
= GetNextVariablePtr (PtrTrack
->CurrPtr
)
1301 if (PtrTrack
->CurrPtr
->State
== VAR_ADDED
||
1302 PtrTrack
->CurrPtr
->State
== (VAR_IN_DELETED_TRANSITION
& VAR_ADDED
)
1304 if (IgnoreRtCheck
|| !AtRuntime () || ((PtrTrack
->CurrPtr
->Attributes
& EFI_VARIABLE_RUNTIME_ACCESS
) != 0)) {
1305 if (VariableName
[0] == 0) {
1306 if (PtrTrack
->CurrPtr
->State
== (VAR_IN_DELETED_TRANSITION
& VAR_ADDED
)) {
1307 InDeletedVariable
= PtrTrack
->CurrPtr
;
1309 PtrTrack
->InDeletedTransitionPtr
= InDeletedVariable
;
1313 if (CompareGuid (VendorGuid
, &PtrTrack
->CurrPtr
->VendorGuid
)) {
1314 Point
= (VOID
*) GetVariableNamePtr (PtrTrack
->CurrPtr
);
1316 ASSERT (NameSizeOfVariable (PtrTrack
->CurrPtr
) != 0);
1317 if (CompareMem (VariableName
, Point
, NameSizeOfVariable (PtrTrack
->CurrPtr
)) == 0) {
1318 if (PtrTrack
->CurrPtr
->State
== (VAR_IN_DELETED_TRANSITION
& VAR_ADDED
)) {
1319 InDeletedVariable
= PtrTrack
->CurrPtr
;
1321 PtrTrack
->InDeletedTransitionPtr
= InDeletedVariable
;
1331 PtrTrack
->CurrPtr
= InDeletedVariable
;
1332 return (PtrTrack
->CurrPtr
== NULL
) ? EFI_NOT_FOUND
: EFI_SUCCESS
;
1337 Finds variable in storage blocks of volatile and non-volatile storage areas.
1339 This code finds variable in storage blocks of volatile and non-volatile storage areas.
1340 If VariableName is an empty string, then we just return the first
1341 qualified variable without comparing VariableName and VendorGuid.
1342 If IgnoreRtCheck is TRUE, then we ignore the EFI_VARIABLE_RUNTIME_ACCESS attribute check
1343 at runtime when searching existing variable, only VariableName and VendorGuid are compared.
1344 Otherwise, variables without EFI_VARIABLE_RUNTIME_ACCESS are not visible at runtime.
1346 @param[in] VariableName Name of the variable to be found.
1347 @param[in] VendorGuid Vendor GUID to be found.
1348 @param[out] PtrTrack VARIABLE_POINTER_TRACK structure for output,
1349 including the range searched and the target position.
1350 @param[in] Global Pointer to VARIABLE_GLOBAL structure, including
1351 base of volatile variable storage area, base of
1352 NV variable storage area, and a lock.
1353 @param[in] IgnoreRtCheck Ignore EFI_VARIABLE_RUNTIME_ACCESS attribute
1354 check at runtime when searching variable.
1356 @retval EFI_INVALID_PARAMETER If VariableName is not an empty string, while
1358 @retval EFI_SUCCESS Variable successfully found.
1359 @retval EFI_NOT_FOUND Variable not found
1364 IN CHAR16
*VariableName
,
1365 IN EFI_GUID
*VendorGuid
,
1366 OUT VARIABLE_POINTER_TRACK
*PtrTrack
,
1367 IN VARIABLE_GLOBAL
*Global
,
1368 IN BOOLEAN IgnoreRtCheck
1372 VARIABLE_STORE_HEADER
*VariableStoreHeader
[VariableStoreTypeMax
];
1373 VARIABLE_STORE_TYPE Type
;
1375 if (VariableName
[0] != 0 && VendorGuid
== NULL
) {
1376 return EFI_INVALID_PARAMETER
;
1380 // 0: Volatile, 1: HOB, 2: Non-Volatile.
1381 // The index and attributes mapping must be kept in this order as RuntimeServiceGetNextVariableName
1382 // make use of this mapping to implement search algorithm.
1384 VariableStoreHeader
[VariableStoreTypeVolatile
] = (VARIABLE_STORE_HEADER
*) (UINTN
) Global
->VolatileVariableBase
;
1385 VariableStoreHeader
[VariableStoreTypeHob
] = (VARIABLE_STORE_HEADER
*) (UINTN
) Global
->HobVariableBase
;
1386 VariableStoreHeader
[VariableStoreTypeNv
] = mNvVariableCache
;
1389 // Find the variable by walk through HOB, volatile and non-volatile variable store.
1391 for (Type
= (VARIABLE_STORE_TYPE
) 0; Type
< VariableStoreTypeMax
; Type
++) {
1392 if (VariableStoreHeader
[Type
] == NULL
) {
1396 PtrTrack
->StartPtr
= GetStartPointer (VariableStoreHeader
[Type
]);
1397 PtrTrack
->EndPtr
= GetEndPointer (VariableStoreHeader
[Type
]);
1398 PtrTrack
->Volatile
= (BOOLEAN
) (Type
== VariableStoreTypeVolatile
);
1400 Status
= FindVariableEx (VariableName
, VendorGuid
, IgnoreRtCheck
, PtrTrack
);
1401 if (!EFI_ERROR (Status
)) {
1405 return EFI_NOT_FOUND
;
1409 Get index from supported language codes according to language string.
1411 This code is used to get corresponding index in supported language codes. It can handle
1412 RFC4646 and ISO639 language tags.
1413 In ISO639 language tags, take 3-characters as a delimitation to find matched string and calculate the index.
1414 In RFC4646 language tags, take semicolon as a delimitation to find matched string and calculate the index.
1417 SupportedLang = "engfraengfra"
1419 Iso639Language = TRUE
1420 The return value is "0".
1422 SupportedLang = "en;fr;en-US;fr-FR"
1424 Iso639Language = FALSE
1425 The return value is "3".
1427 @param SupportedLang Platform supported language codes.
1428 @param Lang Configured language.
1429 @param Iso639Language A bool value to signify if the handler is operated on ISO639 or RFC4646.
1431 @retval The index of language in the language codes.
1435 GetIndexFromSupportedLangCodes(
1436 IN CHAR8
*SupportedLang
,
1438 IN BOOLEAN Iso639Language
1442 UINTN CompareLength
;
1443 UINTN LanguageLength
;
1445 if (Iso639Language
) {
1446 CompareLength
= ISO_639_2_ENTRY_SIZE
;
1447 for (Index
= 0; Index
< AsciiStrLen (SupportedLang
); Index
+= CompareLength
) {
1448 if (AsciiStrnCmp (Lang
, SupportedLang
+ Index
, CompareLength
) == 0) {
1450 // Successfully find the index of Lang string in SupportedLang string.
1452 Index
= Index
/ CompareLength
;
1460 // Compare RFC4646 language code
1463 for (LanguageLength
= 0; Lang
[LanguageLength
] != '\0'; LanguageLength
++);
1465 for (Index
= 0; *SupportedLang
!= '\0'; Index
++, SupportedLang
+= CompareLength
) {
1467 // Skip ';' characters in SupportedLang
1469 for (; *SupportedLang
!= '\0' && *SupportedLang
== ';'; SupportedLang
++);
1471 // Determine the length of the next language code in SupportedLang
1473 for (CompareLength
= 0; SupportedLang
[CompareLength
] != '\0' && SupportedLang
[CompareLength
] != ';'; CompareLength
++);
1475 if ((CompareLength
== LanguageLength
) &&
1476 (AsciiStrnCmp (Lang
, SupportedLang
, CompareLength
) == 0)) {
1478 // Successfully find the index of Lang string in SupportedLang string.
1489 Get language string from supported language codes according to index.
1491 This code is used to get corresponding language strings in supported language codes. It can handle
1492 RFC4646 and ISO639 language tags.
1493 In ISO639 language tags, take 3-characters as a delimitation. Find language string according to the index.
1494 In RFC4646 language tags, take semicolon as a delimitation. Find language string according to the index.
1497 SupportedLang = "engfraengfra"
1499 Iso639Language = TRUE
1500 The return value is "fra".
1502 SupportedLang = "en;fr;en-US;fr-FR"
1504 Iso639Language = FALSE
1505 The return value is "fr".
1507 @param SupportedLang Platform supported language codes.
1508 @param Index The index in supported language codes.
1509 @param Iso639Language A bool value to signify if the handler is operated on ISO639 or RFC4646.
1511 @retval The language string in the language codes.
1515 GetLangFromSupportedLangCodes (
1516 IN CHAR8
*SupportedLang
,
1518 IN BOOLEAN Iso639Language
1522 UINTN CompareLength
;
1526 Supported
= SupportedLang
;
1527 if (Iso639Language
) {
1529 // According to the index of Lang string in SupportedLang string to get the language.
1530 // This code will be invoked in RUNTIME, therefore there is not a memory allocate/free operation.
1531 // In driver entry, it pre-allocates a runtime attribute memory to accommodate this string.
1533 CompareLength
= ISO_639_2_ENTRY_SIZE
;
1534 mVariableModuleGlobal
->Lang
[CompareLength
] = '\0';
1535 return CopyMem (mVariableModuleGlobal
->Lang
, SupportedLang
+ Index
* CompareLength
, CompareLength
);
1540 // Take semicolon as delimitation, sequentially traverse supported language codes.
1542 for (CompareLength
= 0; *Supported
!= ';' && *Supported
!= '\0'; CompareLength
++) {
1545 if ((*Supported
== '\0') && (SubIndex
!= Index
)) {
1547 // Have completed the traverse, but not find corrsponding string.
1548 // This case is not allowed to happen.
1553 if (SubIndex
== Index
) {
1555 // According to the index of Lang string in SupportedLang string to get the language.
1556 // As this code will be invoked in RUNTIME, therefore there is not memory allocate/free operation.
1557 // In driver entry, it pre-allocates a runtime attribute memory to accommodate this string.
1559 mVariableModuleGlobal
->PlatformLang
[CompareLength
] = '\0';
1560 return CopyMem (mVariableModuleGlobal
->PlatformLang
, Supported
- CompareLength
, CompareLength
);
1565 // Skip ';' characters in Supported
1567 for (; *Supported
!= '\0' && *Supported
== ';'; Supported
++);
1573 Returns a pointer to an allocated buffer that contains the best matching language
1574 from a set of supported languages.
1576 This function supports both ISO 639-2 and RFC 4646 language codes, but language
1577 code types may not be mixed in a single call to this function. This function
1578 supports a variable argument list that allows the caller to pass in a prioritized
1579 list of language codes to test against all the language codes in SupportedLanguages.
1581 If SupportedLanguages is NULL, then ASSERT().
1583 @param[in] SupportedLanguages A pointer to a Null-terminated ASCII string that
1584 contains a set of language codes in the format
1585 specified by Iso639Language.
1586 @param[in] Iso639Language If TRUE, then all language codes are assumed to be
1587 in ISO 639-2 format. If FALSE, then all language
1588 codes are assumed to be in RFC 4646 language format
1589 @param[in] ... A variable argument list that contains pointers to
1590 Null-terminated ASCII strings that contain one or more
1591 language codes in the format specified by Iso639Language.
1592 The first language code from each of these language
1593 code lists is used to determine if it is an exact or
1594 close match to any of the language codes in
1595 SupportedLanguages. Close matches only apply to RFC 4646
1596 language codes, and the matching algorithm from RFC 4647
1597 is used to determine if a close match is present. If
1598 an exact or close match is found, then the matching
1599 language code from SupportedLanguages is returned. If
1600 no matches are found, then the next variable argument
1601 parameter is evaluated. The variable argument list
1602 is terminated by a NULL.
1604 @retval NULL The best matching language could not be found in SupportedLanguages.
1605 @retval NULL There are not enough resources available to return the best matching
1607 @retval Other A pointer to a Null-terminated ASCII string that is the best matching
1608 language in SupportedLanguages.
1613 VariableGetBestLanguage (
1614 IN CONST CHAR8
*SupportedLanguages
,
1615 IN BOOLEAN Iso639Language
,
1621 UINTN CompareLength
;
1622 UINTN LanguageLength
;
1623 CONST CHAR8
*Supported
;
1626 if (SupportedLanguages
== NULL
) {
1630 VA_START (Args
, Iso639Language
);
1631 while ((Language
= VA_ARG (Args
, CHAR8
*)) != NULL
) {
1633 // Default to ISO 639-2 mode
1636 LanguageLength
= MIN (3, AsciiStrLen (Language
));
1639 // If in RFC 4646 mode, then determine the length of the first RFC 4646 language code in Language
1641 if (!Iso639Language
) {
1642 for (LanguageLength
= 0; Language
[LanguageLength
] != 0 && Language
[LanguageLength
] != ';'; LanguageLength
++);
1646 // Trim back the length of Language used until it is empty
1648 while (LanguageLength
> 0) {
1650 // Loop through all language codes in SupportedLanguages
1652 for (Supported
= SupportedLanguages
; *Supported
!= '\0'; Supported
+= CompareLength
) {
1654 // In RFC 4646 mode, then Loop through all language codes in SupportedLanguages
1656 if (!Iso639Language
) {
1658 // Skip ';' characters in Supported
1660 for (; *Supported
!= '\0' && *Supported
== ';'; Supported
++);
1662 // Determine the length of the next language code in Supported
1664 for (CompareLength
= 0; Supported
[CompareLength
] != 0 && Supported
[CompareLength
] != ';'; CompareLength
++);
1666 // If Language is longer than the Supported, then skip to the next language
1668 if (LanguageLength
> CompareLength
) {
1673 // See if the first LanguageLength characters in Supported match Language
1675 if (AsciiStrnCmp (Supported
, Language
, LanguageLength
) == 0) {
1678 Buffer
= Iso639Language
? mVariableModuleGlobal
->Lang
: mVariableModuleGlobal
->PlatformLang
;
1679 Buffer
[CompareLength
] = '\0';
1680 return CopyMem (Buffer
, Supported
, CompareLength
);
1684 if (Iso639Language
) {
1686 // If ISO 639 mode, then each language can only be tested once
1691 // If RFC 4646 mode, then trim Language from the right to the next '-' character
1693 for (LanguageLength
--; LanguageLength
> 0 && Language
[LanguageLength
] != '-'; LanguageLength
--);
1700 // No matches were found
1706 This function is to check if the remaining variable space is enough to set
1707 all Variables from argument list successfully. The purpose of the check
1708 is to keep the consistency of the Variables to be in variable storage.
1710 Note: Variables are assumed to be in same storage.
1711 The set sequence of Variables will be same with the sequence of VariableEntry from argument list,
1712 so follow the argument sequence to check the Variables.
1714 @param[in] Attributes Variable attributes for Variable entries.
1715 @param ... The variable argument list with type VARIABLE_ENTRY_CONSISTENCY *.
1716 A NULL terminates the list. The VariableSize of
1717 VARIABLE_ENTRY_CONSISTENCY is the variable data size as input.
1718 It will be changed to variable total size as output.
1720 @retval TRUE Have enough variable space to set the Variables successfully.
1721 @retval FALSE No enough variable space to set the Variables successfully.
1726 CheckRemainingSpaceForConsistency (
1727 IN UINT32 Attributes
,
1733 VARIABLE_ENTRY_CONSISTENCY
*VariableEntry
;
1734 UINT64 MaximumVariableStorageSize
;
1735 UINT64 RemainingVariableStorageSize
;
1736 UINT64 MaximumVariableSize
;
1737 UINTN TotalNeededSize
;
1738 UINTN OriginalVarSize
;
1739 VARIABLE_STORE_HEADER
*VariableStoreHeader
;
1740 VARIABLE_POINTER_TRACK VariablePtrTrack
;
1741 VARIABLE_HEADER
*NextVariable
;
1746 // Non-Volatile related.
1748 VariableStoreHeader
= mNvVariableCache
;
1750 Status
= VariableServiceQueryVariableInfoInternal (
1752 &MaximumVariableStorageSize
,
1753 &RemainingVariableStorageSize
,
1754 &MaximumVariableSize
1756 ASSERT_EFI_ERROR (Status
);
1758 TotalNeededSize
= 0;
1759 VA_START (Args
, Attributes
);
1760 VariableEntry
= VA_ARG (Args
, VARIABLE_ENTRY_CONSISTENCY
*);
1761 while (VariableEntry
!= NULL
) {
1763 // Calculate variable total size.
1765 VarNameSize
= StrSize (VariableEntry
->Name
);
1766 VarNameSize
+= GET_PAD_SIZE (VarNameSize
);
1767 VarDataSize
= VariableEntry
->VariableSize
;
1768 VarDataSize
+= GET_PAD_SIZE (VarDataSize
);
1769 VariableEntry
->VariableSize
= HEADER_ALIGN (sizeof (VARIABLE_HEADER
) + VarNameSize
+ VarDataSize
);
1771 TotalNeededSize
+= VariableEntry
->VariableSize
;
1772 VariableEntry
= VA_ARG (Args
, VARIABLE_ENTRY_CONSISTENCY
*);
1776 if (RemainingVariableStorageSize
>= TotalNeededSize
) {
1778 // Already have enough space.
1781 } else if (AtRuntime ()) {
1783 // At runtime, no reclaim.
1784 // The original variable space of Variables can't be reused.
1789 VA_START (Args
, Attributes
);
1790 VariableEntry
= VA_ARG (Args
, VARIABLE_ENTRY_CONSISTENCY
*);
1791 while (VariableEntry
!= NULL
) {
1793 // Check if Variable[Index] has been present and get its size.
1795 OriginalVarSize
= 0;
1796 VariablePtrTrack
.StartPtr
= GetStartPointer (VariableStoreHeader
);
1797 VariablePtrTrack
.EndPtr
= GetEndPointer (VariableStoreHeader
);
1798 Status
= FindVariableEx (
1799 VariableEntry
->Name
,
1800 VariableEntry
->Guid
,
1804 if (!EFI_ERROR (Status
)) {
1806 // Get size of Variable[Index].
1808 NextVariable
= GetNextVariablePtr (VariablePtrTrack
.CurrPtr
);
1809 OriginalVarSize
= (UINTN
) NextVariable
- (UINTN
) VariablePtrTrack
.CurrPtr
;
1811 // Add the original size of Variable[Index] to remaining variable storage size.
1813 RemainingVariableStorageSize
+= OriginalVarSize
;
1815 if (VariableEntry
->VariableSize
> RemainingVariableStorageSize
) {
1817 // No enough space for Variable[Index].
1823 // Sub the (new) size of Variable[Index] from remaining variable storage size.
1825 RemainingVariableStorageSize
-= VariableEntry
->VariableSize
;
1826 VariableEntry
= VA_ARG (Args
, VARIABLE_ENTRY_CONSISTENCY
*);
1834 Hook the operations in PlatformLangCodes, LangCodes, PlatformLang and Lang.
1836 When setting Lang/LangCodes, simultaneously update PlatformLang/PlatformLangCodes.
1838 According to UEFI spec, PlatformLangCodes/LangCodes are only set once in firmware initialization,
1839 and are read-only. Therefore, in variable driver, only store the original value for other use.
1841 @param[in] VariableName Name of variable.
1843 @param[in] Data Variable data.
1845 @param[in] DataSize Size of data. 0 means delete.
1847 @retval EFI_SUCCESS The update operation is successful or ignored.
1848 @retval EFI_WRITE_PROTECTED Update PlatformLangCodes/LangCodes at runtime.
1849 @retval EFI_OUT_OF_RESOURCES No enough variable space to do the update operation.
1850 @retval Others Other errors happened during the update operation.
1854 AutoUpdateLangVariable (
1855 IN CHAR16
*VariableName
,
1861 CHAR8
*BestPlatformLang
;
1865 VARIABLE_POINTER_TRACK Variable
;
1866 BOOLEAN SetLanguageCodes
;
1867 VARIABLE_ENTRY_CONSISTENCY VariableEntry
[2];
1870 // Don't do updates for delete operation
1872 if (DataSize
== 0) {
1876 SetLanguageCodes
= FALSE
;
1878 if (StrCmp (VariableName
, EFI_PLATFORM_LANG_CODES_VARIABLE_NAME
) == 0) {
1880 // PlatformLangCodes is a volatile variable, so it can not be updated at runtime.
1883 return EFI_WRITE_PROTECTED
;
1886 SetLanguageCodes
= TRUE
;
1889 // According to UEFI spec, PlatformLangCodes is only set once in firmware initialization, and is read-only
1890 // Therefore, in variable driver, only store the original value for other use.
1892 if (mVariableModuleGlobal
->PlatformLangCodes
!= NULL
) {
1893 FreePool (mVariableModuleGlobal
->PlatformLangCodes
);
1895 mVariableModuleGlobal
->PlatformLangCodes
= AllocateRuntimeCopyPool (DataSize
, Data
);
1896 ASSERT (mVariableModuleGlobal
->PlatformLangCodes
!= NULL
);
1899 // PlatformLang holds a single language from PlatformLangCodes,
1900 // so the size of PlatformLangCodes is enough for the PlatformLang.
1902 if (mVariableModuleGlobal
->PlatformLang
!= NULL
) {
1903 FreePool (mVariableModuleGlobal
->PlatformLang
);
1905 mVariableModuleGlobal
->PlatformLang
= AllocateRuntimePool (DataSize
);
1906 ASSERT (mVariableModuleGlobal
->PlatformLang
!= NULL
);
1908 } else if (StrCmp (VariableName
, EFI_LANG_CODES_VARIABLE_NAME
) == 0) {
1910 // LangCodes is a volatile variable, so it can not be updated at runtime.
1913 return EFI_WRITE_PROTECTED
;
1916 SetLanguageCodes
= TRUE
;
1919 // According to UEFI spec, LangCodes is only set once in firmware initialization, and is read-only
1920 // Therefore, in variable driver, only store the original value for other use.
1922 if (mVariableModuleGlobal
->LangCodes
!= NULL
) {
1923 FreePool (mVariableModuleGlobal
->LangCodes
);
1925 mVariableModuleGlobal
->LangCodes
= AllocateRuntimeCopyPool (DataSize
, Data
);
1926 ASSERT (mVariableModuleGlobal
->LangCodes
!= NULL
);
1929 if (SetLanguageCodes
1930 && (mVariableModuleGlobal
->PlatformLangCodes
!= NULL
)
1931 && (mVariableModuleGlobal
->LangCodes
!= NULL
)) {
1933 // Update Lang if PlatformLang is already set
1934 // Update PlatformLang if Lang is already set
1936 Status
= FindVariable (EFI_PLATFORM_LANG_VARIABLE_NAME
, &gEfiGlobalVariableGuid
, &Variable
, &mVariableModuleGlobal
->VariableGlobal
, FALSE
);
1937 if (!EFI_ERROR (Status
)) {
1941 VariableName
= EFI_PLATFORM_LANG_VARIABLE_NAME
;
1942 Data
= GetVariableDataPtr (Variable
.CurrPtr
);
1943 DataSize
= Variable
.CurrPtr
->DataSize
;
1945 Status
= FindVariable (EFI_LANG_VARIABLE_NAME
, &gEfiGlobalVariableGuid
, &Variable
, &mVariableModuleGlobal
->VariableGlobal
, FALSE
);
1946 if (!EFI_ERROR (Status
)) {
1948 // Update PlatformLang
1950 VariableName
= EFI_LANG_VARIABLE_NAME
;
1951 Data
= GetVariableDataPtr (Variable
.CurrPtr
);
1952 DataSize
= Variable
.CurrPtr
->DataSize
;
1955 // Neither PlatformLang nor Lang is set, directly return
1962 Status
= EFI_SUCCESS
;
1965 // According to UEFI spec, "Lang" and "PlatformLang" is NV|BS|RT attributions.
1967 Attributes
= EFI_VARIABLE_NON_VOLATILE
| EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_RUNTIME_ACCESS
;
1969 if (StrCmp (VariableName
, EFI_PLATFORM_LANG_VARIABLE_NAME
) == 0) {
1971 // Update Lang when PlatformLangCodes/LangCodes were set.
1973 if ((mVariableModuleGlobal
->PlatformLangCodes
!= NULL
) && (mVariableModuleGlobal
->LangCodes
!= NULL
)) {
1975 // When setting PlatformLang, firstly get most matched language string from supported language codes.
1977 BestPlatformLang
= VariableGetBestLanguage (mVariableModuleGlobal
->PlatformLangCodes
, FALSE
, Data
, NULL
);
1978 if (BestPlatformLang
!= NULL
) {
1980 // Get the corresponding index in language codes.
1982 Index
= GetIndexFromSupportedLangCodes (mVariableModuleGlobal
->PlatformLangCodes
, BestPlatformLang
, FALSE
);
1985 // Get the corresponding ISO639 language tag according to RFC4646 language tag.
1987 BestLang
= GetLangFromSupportedLangCodes (mVariableModuleGlobal
->LangCodes
, Index
, TRUE
);
1990 // Check the variable space for both Lang and PlatformLang variable.
1992 VariableEntry
[0].VariableSize
= ISO_639_2_ENTRY_SIZE
+ 1;
1993 VariableEntry
[0].Guid
= &gEfiGlobalVariableGuid
;
1994 VariableEntry
[0].Name
= EFI_LANG_VARIABLE_NAME
;
1996 VariableEntry
[1].VariableSize
= AsciiStrSize (BestPlatformLang
);
1997 VariableEntry
[1].Guid
= &gEfiGlobalVariableGuid
;
1998 VariableEntry
[1].Name
= EFI_PLATFORM_LANG_VARIABLE_NAME
;
1999 if (!CheckRemainingSpaceForConsistency (VARIABLE_ATTRIBUTE_NV_BS_RT
, &VariableEntry
[0], &VariableEntry
[1], NULL
)) {
2001 // No enough variable space to set both Lang and PlatformLang successfully.
2003 Status
= EFI_OUT_OF_RESOURCES
;
2006 // Successfully convert PlatformLang to Lang, and set the BestLang value into Lang variable simultaneously.
2008 FindVariable (EFI_LANG_VARIABLE_NAME
, &gEfiGlobalVariableGuid
, &Variable
, &mVariableModuleGlobal
->VariableGlobal
, FALSE
);
2010 Status
= UpdateVariable (EFI_LANG_VARIABLE_NAME
, &gEfiGlobalVariableGuid
, BestLang
,
2011 ISO_639_2_ENTRY_SIZE
+ 1, Attributes
, 0, 0, &Variable
, NULL
);
2014 DEBUG ((EFI_D_INFO
, "Variable Driver Auto Update PlatformLang, PlatformLang:%a, Lang:%a Status: %r\n", BestPlatformLang
, BestLang
, Status
));
2018 } else if (StrCmp (VariableName
, EFI_LANG_VARIABLE_NAME
) == 0) {
2020 // Update PlatformLang when PlatformLangCodes/LangCodes were set.
2022 if ((mVariableModuleGlobal
->PlatformLangCodes
!= NULL
) && (mVariableModuleGlobal
->LangCodes
!= NULL
)) {
2024 // When setting Lang, firstly get most matched language string from supported language codes.
2026 BestLang
= VariableGetBestLanguage (mVariableModuleGlobal
->LangCodes
, TRUE
, Data
, NULL
);
2027 if (BestLang
!= NULL
) {
2029 // Get the corresponding index in language codes.
2031 Index
= GetIndexFromSupportedLangCodes (mVariableModuleGlobal
->LangCodes
, BestLang
, TRUE
);
2034 // Get the corresponding RFC4646 language tag according to ISO639 language tag.
2036 BestPlatformLang
= GetLangFromSupportedLangCodes (mVariableModuleGlobal
->PlatformLangCodes
, Index
, FALSE
);
2039 // Check the variable space for both PlatformLang and Lang variable.
2041 VariableEntry
[0].VariableSize
= AsciiStrSize (BestPlatformLang
);
2042 VariableEntry
[0].Guid
= &gEfiGlobalVariableGuid
;
2043 VariableEntry
[0].Name
= EFI_PLATFORM_LANG_VARIABLE_NAME
;
2045 VariableEntry
[1].VariableSize
= ISO_639_2_ENTRY_SIZE
+ 1;
2046 VariableEntry
[1].Guid
= &gEfiGlobalVariableGuid
;
2047 VariableEntry
[1].Name
= EFI_LANG_VARIABLE_NAME
;
2048 if (!CheckRemainingSpaceForConsistency (VARIABLE_ATTRIBUTE_NV_BS_RT
, &VariableEntry
[0], &VariableEntry
[1], NULL
)) {
2050 // No enough variable space to set both PlatformLang and Lang successfully.
2052 Status
= EFI_OUT_OF_RESOURCES
;
2055 // Successfully convert Lang to PlatformLang, and set the BestPlatformLang value into PlatformLang variable simultaneously.
2057 FindVariable (EFI_PLATFORM_LANG_VARIABLE_NAME
, &gEfiGlobalVariableGuid
, &Variable
, &mVariableModuleGlobal
->VariableGlobal
, FALSE
);
2059 Status
= UpdateVariable (EFI_PLATFORM_LANG_VARIABLE_NAME
, &gEfiGlobalVariableGuid
, BestPlatformLang
,
2060 AsciiStrSize (BestPlatformLang
), Attributes
, 0, 0, &Variable
, NULL
);
2063 DEBUG ((EFI_D_INFO
, "Variable Driver Auto Update Lang, Lang:%a, PlatformLang:%a Status: %r\n", BestLang
, BestPlatformLang
, Status
));
2068 if (SetLanguageCodes
) {
2070 // Continue to set PlatformLangCodes or LangCodes.
2079 Update the variable region with Variable information. If EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS is set,
2080 index of associated public key is needed.
2082 @param[in] VariableName Name of variable.
2083 @param[in] VendorGuid Guid of variable.
2084 @param[in] Data Variable data.
2085 @param[in] DataSize Size of data. 0 means delete.
2086 @param[in] Attributes Attributes of the variable.
2087 @param[in] KeyIndex Index of associated public key.
2088 @param[in] MonotonicCount Value of associated monotonic count.
2089 @param[in, out] CacheVariable The variable information which is used to keep track of variable usage.
2090 @param[in] TimeStamp Value of associated TimeStamp.
2092 @retval EFI_SUCCESS The update operation is success.
2093 @retval EFI_OUT_OF_RESOURCES Variable region is full, can not write other data into this region.
2098 IN CHAR16
*VariableName
,
2099 IN EFI_GUID
*VendorGuid
,
2102 IN UINT32 Attributes OPTIONAL
,
2103 IN UINT32 KeyIndex OPTIONAL
,
2104 IN UINT64 MonotonicCount OPTIONAL
,
2105 IN OUT VARIABLE_POINTER_TRACK
*CacheVariable
,
2106 IN EFI_TIME
*TimeStamp OPTIONAL
2110 VARIABLE_HEADER
*NextVariable
;
2113 UINTN VarNameOffset
;
2114 UINTN VarDataOffset
;
2118 EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*Fvb
;
2120 VARIABLE_POINTER_TRACK
*Variable
;
2121 VARIABLE_POINTER_TRACK NvVariable
;
2122 VARIABLE_STORE_HEADER
*VariableStoreHeader
;
2124 UINT8
*BufferForMerge
;
2125 UINTN MergedBufSize
;
2128 BOOLEAN IsCommonVariable
;
2129 BOOLEAN IsCommonUserVariable
;
2131 if (mVariableModuleGlobal
->FvbInstance
== NULL
) {
2133 // The FVB protocol is not installed, so the EFI_VARIABLE_WRITE_ARCH_PROTOCOL is not installed.
2135 if ((Attributes
& EFI_VARIABLE_NON_VOLATILE
) != 0) {
2137 // Trying to update NV variable prior to the installation of EFI_VARIABLE_WRITE_ARCH_PROTOCOL
2139 return EFI_NOT_AVAILABLE_YET
;
2140 } else if ((Attributes
& EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS
) != 0) {
2142 // Trying to update volatile authenticated variable prior to the installation of EFI_VARIABLE_WRITE_ARCH_PROTOCOL
2143 // The authenticated variable perhaps is not initialized, just return here.
2145 return EFI_NOT_AVAILABLE_YET
;
2149 if ((CacheVariable
->CurrPtr
== NULL
) || CacheVariable
->Volatile
) {
2150 Variable
= CacheVariable
;
2153 // Update/Delete existing NV variable.
2154 // CacheVariable points to the variable in the memory copy of Flash area
2155 // Now let Variable points to the same variable in Flash area.
2157 VariableStoreHeader
= (VARIABLE_STORE_HEADER
*) ((UINTN
) mVariableModuleGlobal
->VariableGlobal
.NonVolatileVariableBase
);
2158 Variable
= &NvVariable
;
2159 Variable
->StartPtr
= GetStartPointer (VariableStoreHeader
);
2160 Variable
->EndPtr
= GetEndPointer (VariableStoreHeader
);
2161 Variable
->CurrPtr
= (VARIABLE_HEADER
*)((UINTN
)Variable
->StartPtr
+ ((UINTN
)CacheVariable
->CurrPtr
- (UINTN
)CacheVariable
->StartPtr
));
2162 if (CacheVariable
->InDeletedTransitionPtr
!= NULL
) {
2163 Variable
->InDeletedTransitionPtr
= (VARIABLE_HEADER
*)((UINTN
)Variable
->StartPtr
+ ((UINTN
)CacheVariable
->InDeletedTransitionPtr
- (UINTN
)CacheVariable
->StartPtr
));
2165 Variable
->InDeletedTransitionPtr
= NULL
;
2167 Variable
->Volatile
= FALSE
;
2170 Fvb
= mVariableModuleGlobal
->FvbInstance
;
2173 // Tricky part: Use scratch data area at the end of volatile variable store
2174 // as a temporary storage.
2176 NextVariable
= GetEndPointer ((VARIABLE_STORE_HEADER
*) ((UINTN
) mVariableModuleGlobal
->VariableGlobal
.VolatileVariableBase
));
2177 ScratchSize
= MAX (PcdGet32 (PcdMaxVariableSize
), PcdGet32 (PcdMaxHardwareErrorVariableSize
));
2178 SetMem (NextVariable
, ScratchSize
, 0xff);
2181 if (Variable
->CurrPtr
!= NULL
) {
2183 // Update/Delete existing variable.
2187 // If AtRuntime and the variable is Volatile and Runtime Access,
2188 // the volatile is ReadOnly, and SetVariable should be aborted and
2189 // return EFI_WRITE_PROTECTED.
2191 if (Variable
->Volatile
) {
2192 Status
= EFI_WRITE_PROTECTED
;
2196 // Only variable that have NV attributes can be updated/deleted in Runtime.
2198 if ((Variable
->CurrPtr
->Attributes
& EFI_VARIABLE_NON_VOLATILE
) == 0) {
2199 Status
= EFI_INVALID_PARAMETER
;
2204 // Only variable that have RT attributes can be updated/deleted in Runtime.
2206 if ((Variable
->CurrPtr
->Attributes
& EFI_VARIABLE_RUNTIME_ACCESS
) == 0) {
2207 Status
= EFI_INVALID_PARAMETER
;
2213 // Setting a data variable with no access, or zero DataSize attributes
2214 // causes it to be deleted.
2215 // When the EFI_VARIABLE_APPEND_WRITE attribute is set, DataSize of zero will
2216 // not delete the variable.
2218 if ((((Attributes
& EFI_VARIABLE_APPEND_WRITE
) == 0) && (DataSize
== 0))|| ((Attributes
& (EFI_VARIABLE_RUNTIME_ACCESS
| EFI_VARIABLE_BOOTSERVICE_ACCESS
)) == 0)) {
2219 if (Variable
->InDeletedTransitionPtr
!= NULL
) {
2221 // Both ADDED and IN_DELETED_TRANSITION variable are present,
2222 // set IN_DELETED_TRANSITION one to DELETED state first.
2224 State
= Variable
->InDeletedTransitionPtr
->State
;
2225 State
&= VAR_DELETED
;
2226 Status
= UpdateVariableStore (
2227 &mVariableModuleGlobal
->VariableGlobal
,
2231 (UINTN
) &Variable
->InDeletedTransitionPtr
->State
,
2235 if (!EFI_ERROR (Status
)) {
2236 if (!Variable
->Volatile
) {
2237 ASSERT (CacheVariable
->InDeletedTransitionPtr
!= NULL
);
2238 CacheVariable
->InDeletedTransitionPtr
->State
= State
;
2245 State
= Variable
->CurrPtr
->State
;
2246 State
&= VAR_DELETED
;
2248 Status
= UpdateVariableStore (
2249 &mVariableModuleGlobal
->VariableGlobal
,
2253 (UINTN
) &Variable
->CurrPtr
->State
,
2257 if (!EFI_ERROR (Status
)) {
2258 UpdateVariableInfo (VariableName
, VendorGuid
, Variable
->Volatile
, FALSE
, FALSE
, TRUE
, FALSE
);
2259 if (!Variable
->Volatile
) {
2260 CacheVariable
->CurrPtr
->State
= State
;
2261 FlushHobVariableToFlash (VariableName
, VendorGuid
);
2267 // If the variable is marked valid, and the same data has been passed in,
2268 // then return to the caller immediately.
2270 if (DataSizeOfVariable (Variable
->CurrPtr
) == DataSize
&&
2271 (CompareMem (Data
, GetVariableDataPtr (Variable
->CurrPtr
), DataSize
) == 0) &&
2272 ((Attributes
& EFI_VARIABLE_APPEND_WRITE
) == 0) &&
2273 (TimeStamp
== NULL
)) {
2275 // Variable content unchanged and no need to update timestamp, just return.
2277 UpdateVariableInfo (VariableName
, VendorGuid
, Variable
->Volatile
, FALSE
, TRUE
, FALSE
, FALSE
);
2278 Status
= EFI_SUCCESS
;
2280 } else if ((Variable
->CurrPtr
->State
== VAR_ADDED
) ||
2281 (Variable
->CurrPtr
->State
== (VAR_ADDED
& VAR_IN_DELETED_TRANSITION
))) {
2284 // EFI_VARIABLE_APPEND_WRITE attribute only effects for existing variable
2286 if ((Attributes
& EFI_VARIABLE_APPEND_WRITE
) != 0) {
2288 // NOTE: From 0 to DataOffset of NextVariable is reserved for Variable Header and Name.
2289 // From DataOffset of NextVariable is to save the existing variable data.
2291 DataOffset
= sizeof (VARIABLE_HEADER
) + Variable
->CurrPtr
->NameSize
+ GET_PAD_SIZE (Variable
->CurrPtr
->NameSize
);
2292 BufferForMerge
= (UINT8
*) ((UINTN
) NextVariable
+ DataOffset
);
2293 CopyMem (BufferForMerge
, (UINT8
*) ((UINTN
) Variable
->CurrPtr
+ DataOffset
), Variable
->CurrPtr
->DataSize
);
2296 // Set Max Common Variable Data Size as default MaxDataSize
2298 MaxDataSize
= PcdGet32 (PcdMaxVariableSize
) - DataOffset
;
2300 if ((CompareGuid (VendorGuid
, &gEfiImageSecurityDatabaseGuid
) &&
2301 ((StrCmp (VariableName
, EFI_IMAGE_SECURITY_DATABASE
) == 0) || (StrCmp (VariableName
, EFI_IMAGE_SECURITY_DATABASE1
) == 0) ||
2302 (StrCmp (VariableName
, EFI_IMAGE_SECURITY_DATABASE2
) == 0))) ||
2303 (CompareGuid (VendorGuid
, &gEfiGlobalVariableGuid
) && (StrCmp (VariableName
, EFI_KEY_EXCHANGE_KEY_NAME
) == 0))) {
2305 // For variables with formatted as EFI_SIGNATURE_LIST, the driver shall not perform an append of
2306 // EFI_SIGNATURE_DATA values that are already part of the existing variable value.
2308 Status
= AppendSignatureList (
2310 Variable
->CurrPtr
->DataSize
,
2311 MaxDataSize
- Variable
->CurrPtr
->DataSize
,
2316 if (Status
== EFI_BUFFER_TOO_SMALL
) {
2318 // Signature List is too long, Failed to Append.
2320 Status
= EFI_INVALID_PARAMETER
;
2324 if (MergedBufSize
== Variable
->CurrPtr
->DataSize
) {
2325 if ((TimeStamp
== NULL
) || CompareTimeStamp (TimeStamp
, &Variable
->CurrPtr
->TimeStamp
)) {
2327 // New EFI_SIGNATURE_DATA is not found and timestamp is not later
2328 // than current timestamp, return EFI_SUCCESS directly.
2330 UpdateVariableInfo (VariableName
, VendorGuid
, Variable
->Volatile
, FALSE
, TRUE
, FALSE
, FALSE
);
2331 Status
= EFI_SUCCESS
;
2337 // For other Variables, append the new data to the end of existing data.
2338 // Max Harware error record variable data size is different from common variable
2340 if ((Attributes
& EFI_VARIABLE_HARDWARE_ERROR_RECORD
) == EFI_VARIABLE_HARDWARE_ERROR_RECORD
) {
2341 MaxDataSize
= PcdGet32 (PcdMaxHardwareErrorVariableSize
) - DataOffset
;
2344 if (Variable
->CurrPtr
->DataSize
+ DataSize
> MaxDataSize
) {
2346 // Existing data size + new data size exceed maximum variable size limitation.
2348 Status
= EFI_INVALID_PARAMETER
;
2351 CopyMem ((UINT8
*) ((UINTN
) BufferForMerge
+ Variable
->CurrPtr
->DataSize
), Data
, DataSize
);
2352 MergedBufSize
= Variable
->CurrPtr
->DataSize
+ DataSize
;
2356 // BufferForMerge(from DataOffset of NextVariable) has included the merged existing and new data.
2358 Data
= BufferForMerge
;
2359 DataSize
= MergedBufSize
;
2364 // Mark the old variable as in delete transition.
2366 State
= Variable
->CurrPtr
->State
;
2367 State
&= VAR_IN_DELETED_TRANSITION
;
2369 Status
= UpdateVariableStore (
2370 &mVariableModuleGlobal
->VariableGlobal
,
2374 (UINTN
) &Variable
->CurrPtr
->State
,
2378 if (EFI_ERROR (Status
)) {
2381 if (!Variable
->Volatile
) {
2382 CacheVariable
->CurrPtr
->State
= State
;
2387 // Not found existing variable. Create a new variable.
2390 if ((DataSize
== 0) && ((Attributes
& EFI_VARIABLE_APPEND_WRITE
) != 0)) {
2391 Status
= EFI_SUCCESS
;
2396 // Make sure we are trying to create a new variable.
2397 // Setting a data variable with zero DataSize or no access attributes means to delete it.
2399 if (DataSize
== 0 || (Attributes
& (EFI_VARIABLE_RUNTIME_ACCESS
| EFI_VARIABLE_BOOTSERVICE_ACCESS
)) == 0) {
2400 Status
= EFI_NOT_FOUND
;
2405 // Only variable have NV|RT attribute can be created in Runtime.
2408 (((Attributes
& EFI_VARIABLE_RUNTIME_ACCESS
) == 0) || ((Attributes
& EFI_VARIABLE_NON_VOLATILE
) == 0))) {
2409 Status
= EFI_INVALID_PARAMETER
;
2415 // Function part - create a new variable and copy the data.
2416 // Both update a variable and create a variable will come here.
2418 NextVariable
->StartId
= VARIABLE_DATA
;
2420 // NextVariable->State = VAR_ADDED;
2422 NextVariable
->Reserved
= 0;
2423 NextVariable
->PubKeyIndex
= KeyIndex
;
2424 NextVariable
->MonotonicCount
= MonotonicCount
;
2425 ZeroMem (&NextVariable
->TimeStamp
, sizeof (EFI_TIME
));
2427 if (((Attributes
& EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS
) != 0) &&
2428 (TimeStamp
!= NULL
)) {
2429 if ((Attributes
& EFI_VARIABLE_APPEND_WRITE
) == 0) {
2430 CopyMem (&NextVariable
->TimeStamp
, TimeStamp
, sizeof (EFI_TIME
));
2433 // In the case when the EFI_VARIABLE_APPEND_WRITE attribute is set, only
2434 // when the new TimeStamp value is later than the current timestamp associated
2435 // with the variable, we need associate the new timestamp with the updated value.
2437 if (Variable
->CurrPtr
!= NULL
) {
2438 if (CompareTimeStamp (&Variable
->CurrPtr
->TimeStamp
, TimeStamp
)) {
2439 CopyMem (&NextVariable
->TimeStamp
, TimeStamp
, sizeof (EFI_TIME
));
2446 // The EFI_VARIABLE_APPEND_WRITE attribute will never be set in the returned
2447 // Attributes bitmask parameter of a GetVariable() call.
2449 NextVariable
->Attributes
= Attributes
& (~EFI_VARIABLE_APPEND_WRITE
);
2451 VarNameOffset
= sizeof (VARIABLE_HEADER
);
2452 VarNameSize
= StrSize (VariableName
);
2454 (UINT8
*) ((UINTN
) NextVariable
+ VarNameOffset
),
2458 VarDataOffset
= VarNameOffset
+ VarNameSize
+ GET_PAD_SIZE (VarNameSize
);
2461 // If DataReady is TRUE, it means the variable data has been saved into
2462 // NextVariable during EFI_VARIABLE_APPEND_WRITE operation preparation.
2466 (UINT8
*) ((UINTN
) NextVariable
+ VarDataOffset
),
2472 CopyMem (&NextVariable
->VendorGuid
, VendorGuid
, sizeof (EFI_GUID
));
2474 // There will be pad bytes after Data, the NextVariable->NameSize and
2475 // NextVariable->DataSize should not include pad size so that variable
2476 // service can get actual size in GetVariable.
2478 NextVariable
->NameSize
= (UINT32
)VarNameSize
;
2479 NextVariable
->DataSize
= (UINT32
)DataSize
;
2482 // The actual size of the variable that stores in storage should
2483 // include pad size.
2485 VarSize
= VarDataOffset
+ DataSize
+ GET_PAD_SIZE (DataSize
);
2486 if ((Attributes
& EFI_VARIABLE_NON_VOLATILE
) != 0) {
2488 // Create a nonvolatile variable.
2492 IsCommonVariable
= FALSE
;
2493 IsCommonUserVariable
= FALSE
;
2494 if ((Attributes
& EFI_VARIABLE_HARDWARE_ERROR_RECORD
) == 0) {
2495 IsCommonVariable
= TRUE
;
2496 IsCommonUserVariable
= IsUserVariable (NextVariable
);
2498 if ((((Attributes
& EFI_VARIABLE_HARDWARE_ERROR_RECORD
) != 0)
2499 && ((VarSize
+ mVariableModuleGlobal
->HwErrVariableTotalSize
) > PcdGet32 (PcdHwErrStorageSize
)))
2500 || (IsCommonVariable
&& ((VarSize
+ mVariableModuleGlobal
->CommonVariableTotalSize
) > mVariableModuleGlobal
->CommonVariableSpace
))
2501 || (IsCommonVariable
&& AtRuntime () && ((VarSize
+ mVariableModuleGlobal
->CommonVariableTotalSize
) > mVariableModuleGlobal
->CommonRuntimeVariableSpace
))
2502 || (IsCommonUserVariable
&& ((VarSize
+ mVariableModuleGlobal
->CommonUserVariableTotalSize
) > mVariableModuleGlobal
->CommonMaxUserVariableSpace
))) {
2504 if (IsCommonUserVariable
&& ((VarSize
+ mVariableModuleGlobal
->CommonUserVariableTotalSize
) > mVariableModuleGlobal
->CommonMaxUserVariableSpace
)) {
2505 RecordVarErrorFlag (VAR_ERROR_FLAG_USER_ERROR
, VariableName
, VendorGuid
, Attributes
, VarSize
);
2507 if (IsCommonVariable
&& ((VarSize
+ mVariableModuleGlobal
->CommonVariableTotalSize
) > mVariableModuleGlobal
->CommonRuntimeVariableSpace
)) {
2508 RecordVarErrorFlag (VAR_ERROR_FLAG_SYSTEM_ERROR
, VariableName
, VendorGuid
, Attributes
, VarSize
);
2510 Status
= EFI_OUT_OF_RESOURCES
;
2514 // Perform garbage collection & reclaim operation, and integrate the new variable at the same time.
2517 mVariableModuleGlobal
->VariableGlobal
.NonVolatileVariableBase
,
2518 &mVariableModuleGlobal
->NonVolatileLastVariableOffset
,
2522 HEADER_ALIGN (VarSize
),
2525 if (!EFI_ERROR (Status
)) {
2527 // The new variable has been integrated successfully during reclaiming.
2529 if (Variable
->CurrPtr
!= NULL
) {
2530 CacheVariable
->CurrPtr
= (VARIABLE_HEADER
*)((UINTN
) CacheVariable
->StartPtr
+ ((UINTN
) Variable
->CurrPtr
- (UINTN
) Variable
->StartPtr
));
2531 CacheVariable
->InDeletedTransitionPtr
= NULL
;
2533 UpdateVariableInfo (VariableName
, VendorGuid
, FALSE
, FALSE
, TRUE
, FALSE
, FALSE
);
2534 FlushHobVariableToFlash (VariableName
, VendorGuid
);
2536 if (IsCommonUserVariable
&& ((VarSize
+ mVariableModuleGlobal
->CommonUserVariableTotalSize
) > mVariableModuleGlobal
->CommonMaxUserVariableSpace
)) {
2537 RecordVarErrorFlag (VAR_ERROR_FLAG_USER_ERROR
, VariableName
, VendorGuid
, Attributes
, VarSize
);
2539 if (IsCommonVariable
&& ((VarSize
+ mVariableModuleGlobal
->CommonVariableTotalSize
) > mVariableModuleGlobal
->CommonVariableSpace
)) {
2540 RecordVarErrorFlag (VAR_ERROR_FLAG_SYSTEM_ERROR
, VariableName
, VendorGuid
, Attributes
, VarSize
);
2547 // 1. Write variable header
2548 // 2. Set variable state to header valid
2549 // 3. Write variable data
2550 // 4. Set variable state to valid
2555 CacheOffset
= mVariableModuleGlobal
->NonVolatileLastVariableOffset
;
2556 Status
= UpdateVariableStore (
2557 &mVariableModuleGlobal
->VariableGlobal
,
2561 mVariableModuleGlobal
->NonVolatileLastVariableOffset
,
2562 sizeof (VARIABLE_HEADER
),
2563 (UINT8
*) NextVariable
2566 if (EFI_ERROR (Status
)) {
2573 NextVariable
->State
= VAR_HEADER_VALID_ONLY
;
2574 Status
= UpdateVariableStore (
2575 &mVariableModuleGlobal
->VariableGlobal
,
2579 mVariableModuleGlobal
->NonVolatileLastVariableOffset
+ OFFSET_OF (VARIABLE_HEADER
, State
),
2581 &NextVariable
->State
2584 if (EFI_ERROR (Status
)) {
2590 Status
= UpdateVariableStore (
2591 &mVariableModuleGlobal
->VariableGlobal
,
2595 mVariableModuleGlobal
->NonVolatileLastVariableOffset
+ sizeof (VARIABLE_HEADER
),
2596 (UINT32
) VarSize
- sizeof (VARIABLE_HEADER
),
2597 (UINT8
*) NextVariable
+ sizeof (VARIABLE_HEADER
)
2600 if (EFI_ERROR (Status
)) {
2606 NextVariable
->State
= VAR_ADDED
;
2607 Status
= UpdateVariableStore (
2608 &mVariableModuleGlobal
->VariableGlobal
,
2612 mVariableModuleGlobal
->NonVolatileLastVariableOffset
+ OFFSET_OF (VARIABLE_HEADER
, State
),
2614 &NextVariable
->State
2617 if (EFI_ERROR (Status
)) {
2621 mVariableModuleGlobal
->NonVolatileLastVariableOffset
+= HEADER_ALIGN (VarSize
);
2623 if ((Attributes
& EFI_VARIABLE_HARDWARE_ERROR_RECORD
) != 0) {
2624 mVariableModuleGlobal
->HwErrVariableTotalSize
+= HEADER_ALIGN (VarSize
);
2626 mVariableModuleGlobal
->CommonVariableTotalSize
+= HEADER_ALIGN (VarSize
);
2627 if (IsCommonUserVariable
) {
2628 mVariableModuleGlobal
->CommonUserVariableTotalSize
+= HEADER_ALIGN (VarSize
);
2632 // update the memory copy of Flash region.
2634 CopyMem ((UINT8
*)mNvVariableCache
+ CacheOffset
, (UINT8
*)NextVariable
, VarSize
);
2637 // Create a volatile variable.
2641 if ((UINT32
) (VarSize
+ mVariableModuleGlobal
->VolatileLastVariableOffset
) >
2642 ((VARIABLE_STORE_HEADER
*) ((UINTN
) (mVariableModuleGlobal
->VariableGlobal
.VolatileVariableBase
)))->Size
) {
2644 // Perform garbage collection & reclaim operation, and integrate the new variable at the same time.
2647 mVariableModuleGlobal
->VariableGlobal
.VolatileVariableBase
,
2648 &mVariableModuleGlobal
->VolatileLastVariableOffset
,
2652 HEADER_ALIGN (VarSize
),
2655 if (!EFI_ERROR (Status
)) {
2657 // The new variable has been integrated successfully during reclaiming.
2659 if (Variable
->CurrPtr
!= NULL
) {
2660 CacheVariable
->CurrPtr
= (VARIABLE_HEADER
*)((UINTN
) CacheVariable
->StartPtr
+ ((UINTN
) Variable
->CurrPtr
- (UINTN
) Variable
->StartPtr
));
2661 CacheVariable
->InDeletedTransitionPtr
= NULL
;
2663 UpdateVariableInfo (VariableName
, VendorGuid
, TRUE
, FALSE
, TRUE
, FALSE
, FALSE
);
2668 NextVariable
->State
= VAR_ADDED
;
2669 Status
= UpdateVariableStore (
2670 &mVariableModuleGlobal
->VariableGlobal
,
2674 mVariableModuleGlobal
->VolatileLastVariableOffset
,
2676 (UINT8
*) NextVariable
2679 if (EFI_ERROR (Status
)) {
2683 mVariableModuleGlobal
->VolatileLastVariableOffset
+= HEADER_ALIGN (VarSize
);
2687 // Mark the old variable as deleted.
2689 if (!EFI_ERROR (Status
) && Variable
->CurrPtr
!= NULL
) {
2690 if (Variable
->InDeletedTransitionPtr
!= NULL
) {
2692 // Both ADDED and IN_DELETED_TRANSITION old variable are present,
2693 // set IN_DELETED_TRANSITION one to DELETED state first.
2695 State
= Variable
->InDeletedTransitionPtr
->State
;
2696 State
&= VAR_DELETED
;
2697 Status
= UpdateVariableStore (
2698 &mVariableModuleGlobal
->VariableGlobal
,
2702 (UINTN
) &Variable
->InDeletedTransitionPtr
->State
,
2706 if (!EFI_ERROR (Status
)) {
2707 if (!Variable
->Volatile
) {
2708 ASSERT (CacheVariable
->InDeletedTransitionPtr
!= NULL
);
2709 CacheVariable
->InDeletedTransitionPtr
->State
= State
;
2716 State
= Variable
->CurrPtr
->State
;
2717 State
&= VAR_DELETED
;
2719 Status
= UpdateVariableStore (
2720 &mVariableModuleGlobal
->VariableGlobal
,
2724 (UINTN
) &Variable
->CurrPtr
->State
,
2728 if (!EFI_ERROR (Status
) && !Variable
->Volatile
) {
2729 CacheVariable
->CurrPtr
->State
= State
;
2733 if (!EFI_ERROR (Status
)) {
2734 UpdateVariableInfo (VariableName
, VendorGuid
, Volatile
, FALSE
, TRUE
, FALSE
, FALSE
);
2736 FlushHobVariableToFlash (VariableName
, VendorGuid
);
2745 Check if a Unicode character is a hexadecimal character.
2747 This function checks if a Unicode character is a
2748 hexadecimal character. The valid hexadecimal character is
2749 L'0' to L'9', L'a' to L'f', or L'A' to L'F'.
2752 @param Char The character to check against.
2754 @retval TRUE If the Char is a hexadecmial character.
2755 @retval FALSE If the Char is not a hexadecmial character.
2760 IsHexaDecimalDigitCharacter (
2764 return (BOOLEAN
) ((Char
>= L
'0' && Char
<= L
'9') || (Char
>= L
'A' && Char
<= L
'F') || (Char
>= L
'a' && Char
<= L
'f'));
2769 This code checks if variable is hardware error record variable or not.
2771 According to UEFI spec, hardware error record variable should use the EFI_HARDWARE_ERROR_VARIABLE VendorGuid
2772 and have the L"HwErrRec####" name convention, #### is a printed hex value and no 0x or h is included in the hex value.
2774 @param VariableName Pointer to variable name.
2775 @param VendorGuid Variable Vendor Guid.
2777 @retval TRUE Variable is hardware error record variable.
2778 @retval FALSE Variable is not hardware error record variable.
2783 IsHwErrRecVariable (
2784 IN CHAR16
*VariableName
,
2785 IN EFI_GUID
*VendorGuid
2788 if (!CompareGuid (VendorGuid
, &gEfiHardwareErrorVariableGuid
) ||
2789 (StrLen (VariableName
) != StrLen (L
"HwErrRec####")) ||
2790 (StrnCmp(VariableName
, L
"HwErrRec", StrLen (L
"HwErrRec")) != 0) ||
2791 !IsHexaDecimalDigitCharacter (VariableName
[0x8]) ||
2792 !IsHexaDecimalDigitCharacter (VariableName
[0x9]) ||
2793 !IsHexaDecimalDigitCharacter (VariableName
[0xA]) ||
2794 !IsHexaDecimalDigitCharacter (VariableName
[0xB])) {
2802 Mark a variable that will become read-only after leaving the DXE phase of execution.
2804 @param[in] This The VARIABLE_LOCK_PROTOCOL instance.
2805 @param[in] VariableName A pointer to the variable name that will be made read-only subsequently.
2806 @param[in] VendorGuid A pointer to the vendor GUID that will be made read-only subsequently.
2808 @retval EFI_SUCCESS The variable specified by the VariableName and the VendorGuid was marked
2809 as pending to be read-only.
2810 @retval EFI_INVALID_PARAMETER VariableName or VendorGuid is NULL.
2811 Or VariableName is an empty string.
2812 @retval EFI_ACCESS_DENIED EFI_END_OF_DXE_EVENT_GROUP_GUID or EFI_EVENT_GROUP_READY_TO_BOOT has
2813 already been signaled.
2814 @retval EFI_OUT_OF_RESOURCES There is not enough resource to hold the lock request.
2818 VariableLockRequestToLock (
2819 IN CONST EDKII_VARIABLE_LOCK_PROTOCOL
*This
,
2820 IN CHAR16
*VariableName
,
2821 IN EFI_GUID
*VendorGuid
2824 VARIABLE_ENTRY
*Entry
;
2827 if (VariableName
== NULL
|| VariableName
[0] == 0 || VendorGuid
== NULL
) {
2828 return EFI_INVALID_PARAMETER
;
2832 return EFI_ACCESS_DENIED
;
2835 Entry
= AllocateRuntimeZeroPool (sizeof (*Entry
) + StrSize (VariableName
));
2836 if (Entry
== NULL
) {
2837 return EFI_OUT_OF_RESOURCES
;
2840 DEBUG ((EFI_D_INFO
, "[Variable] Lock: %g:%s\n", VendorGuid
, VariableName
));
2842 AcquireLockOnlyAtBootTime(&mVariableModuleGlobal
->VariableGlobal
.VariableServicesLock
);
2844 Name
= (CHAR16
*) ((UINTN
) Entry
+ sizeof (*Entry
));
2845 StrnCpy (Name
, VariableName
, StrLen (VariableName
));
2846 CopyGuid (&Entry
->Guid
, VendorGuid
);
2847 InsertTailList (&mLockedVariableList
, &Entry
->Link
);
2849 ReleaseLockOnlyAtBootTime (&mVariableModuleGlobal
->VariableGlobal
.VariableServicesLock
);
2856 This code finds variable in storage blocks (Volatile or Non-Volatile).
2858 Caution: This function may receive untrusted input.
2859 This function may be invoked in SMM mode, and datasize is external input.
2860 This function will do basic validation, before parse the data.
2862 @param VariableName Name of Variable to be found.
2863 @param VendorGuid Variable vendor GUID.
2864 @param Attributes Attribute value of the variable found.
2865 @param DataSize Size of Data found. If size is less than the
2866 data, this value contains the required size.
2867 @param Data Data pointer.
2869 @return EFI_INVALID_PARAMETER Invalid parameter.
2870 @return EFI_SUCCESS Find the specified variable.
2871 @return EFI_NOT_FOUND Not found.
2872 @return EFI_BUFFER_TO_SMALL DataSize is too small for the result.
2877 VariableServiceGetVariable (
2878 IN CHAR16
*VariableName
,
2879 IN EFI_GUID
*VendorGuid
,
2880 OUT UINT32
*Attributes OPTIONAL
,
2881 IN OUT UINTN
*DataSize
,
2886 VARIABLE_POINTER_TRACK Variable
;
2889 if (VariableName
== NULL
|| VendorGuid
== NULL
|| DataSize
== NULL
) {
2890 return EFI_INVALID_PARAMETER
;
2893 AcquireLockOnlyAtBootTime(&mVariableModuleGlobal
->VariableGlobal
.VariableServicesLock
);
2895 Status
= FindVariable (VariableName
, VendorGuid
, &Variable
, &mVariableModuleGlobal
->VariableGlobal
, FALSE
);
2896 if (Variable
.CurrPtr
== NULL
|| EFI_ERROR (Status
)) {
2903 VarDataSize
= DataSizeOfVariable (Variable
.CurrPtr
);
2904 ASSERT (VarDataSize
!= 0);
2906 if (*DataSize
>= VarDataSize
) {
2908 Status
= EFI_INVALID_PARAMETER
;
2912 CopyMem (Data
, GetVariableDataPtr (Variable
.CurrPtr
), VarDataSize
);
2913 if (Attributes
!= NULL
) {
2914 *Attributes
= Variable
.CurrPtr
->Attributes
;
2917 *DataSize
= VarDataSize
;
2918 UpdateVariableInfo (VariableName
, VendorGuid
, Variable
.Volatile
, TRUE
, FALSE
, FALSE
, FALSE
);
2920 Status
= EFI_SUCCESS
;
2923 *DataSize
= VarDataSize
;
2924 Status
= EFI_BUFFER_TOO_SMALL
;
2929 ReleaseLockOnlyAtBootTime (&mVariableModuleGlobal
->VariableGlobal
.VariableServicesLock
);
2937 This code Finds the Next available variable.
2939 Caution: This function may receive untrusted input.
2940 This function may be invoked in SMM mode. This function will do basic validation, before parse the data.
2942 @param VariableNameSize Size of the variable name.
2943 @param VariableName Pointer to variable name.
2944 @param VendorGuid Variable Vendor Guid.
2946 @return EFI_INVALID_PARAMETER Invalid parameter.
2947 @return EFI_SUCCESS Find the specified variable.
2948 @return EFI_NOT_FOUND Not found.
2949 @return EFI_BUFFER_TO_SMALL DataSize is too small for the result.
2954 VariableServiceGetNextVariableName (
2955 IN OUT UINTN
*VariableNameSize
,
2956 IN OUT CHAR16
*VariableName
,
2957 IN OUT EFI_GUID
*VendorGuid
2960 VARIABLE_STORE_TYPE Type
;
2961 VARIABLE_POINTER_TRACK Variable
;
2962 VARIABLE_POINTER_TRACK VariableInHob
;
2963 VARIABLE_POINTER_TRACK VariablePtrTrack
;
2966 VARIABLE_STORE_HEADER
*VariableStoreHeader
[VariableStoreTypeMax
];
2968 if (VariableNameSize
== NULL
|| VariableName
== NULL
|| VendorGuid
== NULL
) {
2969 return EFI_INVALID_PARAMETER
;
2972 AcquireLockOnlyAtBootTime(&mVariableModuleGlobal
->VariableGlobal
.VariableServicesLock
);
2974 Status
= FindVariable (VariableName
, VendorGuid
, &Variable
, &mVariableModuleGlobal
->VariableGlobal
, FALSE
);
2975 if (Variable
.CurrPtr
== NULL
|| EFI_ERROR (Status
)) {
2979 if (VariableName
[0] != 0) {
2981 // If variable name is not NULL, get next variable.
2983 Variable
.CurrPtr
= GetNextVariablePtr (Variable
.CurrPtr
);
2987 // 0: Volatile, 1: HOB, 2: Non-Volatile.
2988 // The index and attributes mapping must be kept in this order as FindVariable
2989 // makes use of this mapping to implement search algorithm.
2991 VariableStoreHeader
[VariableStoreTypeVolatile
] = (VARIABLE_STORE_HEADER
*) (UINTN
) mVariableModuleGlobal
->VariableGlobal
.VolatileVariableBase
;
2992 VariableStoreHeader
[VariableStoreTypeHob
] = (VARIABLE_STORE_HEADER
*) (UINTN
) mVariableModuleGlobal
->VariableGlobal
.HobVariableBase
;
2993 VariableStoreHeader
[VariableStoreTypeNv
] = mNvVariableCache
;
2997 // Switch from Volatile to HOB, to Non-Volatile.
2999 while (!IsValidVariableHeader (Variable
.CurrPtr
, Variable
.EndPtr
)) {
3001 // Find current storage index
3003 for (Type
= (VARIABLE_STORE_TYPE
) 0; Type
< VariableStoreTypeMax
; Type
++) {
3004 if ((VariableStoreHeader
[Type
] != NULL
) && (Variable
.StartPtr
== GetStartPointer (VariableStoreHeader
[Type
]))) {
3008 ASSERT (Type
< VariableStoreTypeMax
);
3010 // Switch to next storage
3012 for (Type
++; Type
< VariableStoreTypeMax
; Type
++) {
3013 if (VariableStoreHeader
[Type
] != NULL
) {
3018 // Capture the case that
3019 // 1. current storage is the last one, or
3020 // 2. no further storage
3022 if (Type
== VariableStoreTypeMax
) {
3023 Status
= EFI_NOT_FOUND
;
3026 Variable
.StartPtr
= GetStartPointer (VariableStoreHeader
[Type
]);
3027 Variable
.EndPtr
= GetEndPointer (VariableStoreHeader
[Type
]);
3028 Variable
.CurrPtr
= Variable
.StartPtr
;
3032 // Variable is found
3034 if (Variable
.CurrPtr
->State
== VAR_ADDED
|| Variable
.CurrPtr
->State
== (VAR_IN_DELETED_TRANSITION
& VAR_ADDED
)) {
3035 if (!AtRuntime () || ((Variable
.CurrPtr
->Attributes
& EFI_VARIABLE_RUNTIME_ACCESS
) != 0)) {
3036 if (Variable
.CurrPtr
->State
== (VAR_IN_DELETED_TRANSITION
& VAR_ADDED
)) {
3038 // If it is a IN_DELETED_TRANSITION variable,
3039 // and there is also a same ADDED one at the same time,
3042 VariablePtrTrack
.StartPtr
= Variable
.StartPtr
;
3043 VariablePtrTrack
.EndPtr
= Variable
.EndPtr
;
3044 Status
= FindVariableEx (
3045 GetVariableNamePtr (Variable
.CurrPtr
),
3046 &Variable
.CurrPtr
->VendorGuid
,
3050 if (!EFI_ERROR (Status
) && VariablePtrTrack
.CurrPtr
->State
== VAR_ADDED
) {
3051 Variable
.CurrPtr
= GetNextVariablePtr (Variable
.CurrPtr
);
3057 // Don't return NV variable when HOB overrides it
3059 if ((VariableStoreHeader
[VariableStoreTypeHob
] != NULL
) && (VariableStoreHeader
[VariableStoreTypeNv
] != NULL
) &&
3060 (Variable
.StartPtr
== GetStartPointer (VariableStoreHeader
[VariableStoreTypeNv
]))
3062 VariableInHob
.StartPtr
= GetStartPointer (VariableStoreHeader
[VariableStoreTypeHob
]);
3063 VariableInHob
.EndPtr
= GetEndPointer (VariableStoreHeader
[VariableStoreTypeHob
]);
3064 Status
= FindVariableEx (
3065 GetVariableNamePtr (Variable
.CurrPtr
),
3066 &Variable
.CurrPtr
->VendorGuid
,
3070 if (!EFI_ERROR (Status
)) {
3071 Variable
.CurrPtr
= GetNextVariablePtr (Variable
.CurrPtr
);
3076 VarNameSize
= NameSizeOfVariable (Variable
.CurrPtr
);
3077 ASSERT (VarNameSize
!= 0);
3079 if (VarNameSize
<= *VariableNameSize
) {
3080 CopyMem (VariableName
, GetVariableNamePtr (Variable
.CurrPtr
), VarNameSize
);
3081 CopyMem (VendorGuid
, &Variable
.CurrPtr
->VendorGuid
, sizeof (EFI_GUID
));
3082 Status
= EFI_SUCCESS
;
3084 Status
= EFI_BUFFER_TOO_SMALL
;
3087 *VariableNameSize
= VarNameSize
;
3092 Variable
.CurrPtr
= GetNextVariablePtr (Variable
.CurrPtr
);
3096 ReleaseLockOnlyAtBootTime (&mVariableModuleGlobal
->VariableGlobal
.VariableServicesLock
);
3102 This code sets variable in storage blocks (Volatile or Non-Volatile).
3104 Caution: This function may receive untrusted input.
3105 This function may be invoked in SMM mode, and datasize and data are external input.
3106 This function will do basic validation, before parse the data.
3107 This function will parse the authentication carefully to avoid security issues, like
3108 buffer overflow, integer overflow.
3109 This function will check attribute carefully to avoid authentication bypass.
3111 @param VariableName Name of Variable to be found.
3112 @param VendorGuid Variable vendor GUID.
3113 @param Attributes Attribute value of the variable found
3114 @param DataSize Size of Data found. If size is less than the
3115 data, this value contains the required size.
3116 @param Data Data pointer.
3118 @return EFI_INVALID_PARAMETER Invalid parameter.
3119 @return EFI_SUCCESS Set successfully.
3120 @return EFI_OUT_OF_RESOURCES Resource not enough to set variable.
3121 @return EFI_NOT_FOUND Not found.
3122 @return EFI_WRITE_PROTECTED Variable is read-only.
3127 VariableServiceSetVariable (
3128 IN CHAR16
*VariableName
,
3129 IN EFI_GUID
*VendorGuid
,
3130 IN UINT32 Attributes
,
3135 VARIABLE_POINTER_TRACK Variable
;
3137 VARIABLE_HEADER
*NextVariable
;
3138 EFI_PHYSICAL_ADDRESS Point
;
3141 VARIABLE_ENTRY
*Entry
;
3145 // Check input parameters.
3147 if (VariableName
== NULL
|| VariableName
[0] == 0 || VendorGuid
== NULL
) {
3148 return EFI_INVALID_PARAMETER
;
3151 if (DataSize
!= 0 && Data
== NULL
) {
3152 return EFI_INVALID_PARAMETER
;
3156 // Check for reserverd bit in variable attribute.
3158 if ((Attributes
& (~EFI_VARIABLE_ATTRIBUTES_MASK
)) != 0) {
3159 return EFI_INVALID_PARAMETER
;
3163 // Make sure if runtime bit is set, boot service bit is set also.
3165 if ((Attributes
& (EFI_VARIABLE_RUNTIME_ACCESS
| EFI_VARIABLE_BOOTSERVICE_ACCESS
)) == EFI_VARIABLE_RUNTIME_ACCESS
) {
3166 return EFI_INVALID_PARAMETER
;
3170 // EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS and EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS attribute
3171 // cannot be set both.
3173 if (((Attributes
& EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS
) == EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS
)
3174 && ((Attributes
& EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS
) == EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS
)) {
3175 return EFI_INVALID_PARAMETER
;
3178 if ((Attributes
& EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS
) == EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS
) {
3179 if (DataSize
< AUTHINFO_SIZE
) {
3181 // Try to write Authenticated Variable without AuthInfo.
3183 return EFI_SECURITY_VIOLATION
;
3185 PayloadSize
= DataSize
- AUTHINFO_SIZE
;
3186 } else if ((Attributes
& EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS
) == EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS
) {
3188 // Sanity check for EFI_VARIABLE_AUTHENTICATION_2 descriptor.
3190 if (DataSize
< OFFSET_OF_AUTHINFO2_CERT_DATA
||
3191 ((EFI_VARIABLE_AUTHENTICATION_2
*) Data
)->AuthInfo
.Hdr
.dwLength
> DataSize
- (OFFSET_OF (EFI_VARIABLE_AUTHENTICATION_2
, AuthInfo
)) ||
3192 ((EFI_VARIABLE_AUTHENTICATION_2
*) Data
)->AuthInfo
.Hdr
.dwLength
< OFFSET_OF (WIN_CERTIFICATE_UEFI_GUID
, CertData
)) {
3193 return EFI_SECURITY_VIOLATION
;
3195 PayloadSize
= DataSize
- AUTHINFO2_SIZE (Data
);
3197 PayloadSize
= DataSize
;
3200 if ((UINTN
)(~0) - PayloadSize
< StrSize(VariableName
)){
3202 // Prevent whole variable size overflow
3204 return EFI_INVALID_PARAMETER
;
3208 // The size of the VariableName, including the Unicode Null in bytes plus
3209 // the DataSize is limited to maximum size of PcdGet32 (PcdMaxHardwareErrorVariableSize)
3210 // bytes for HwErrRec, and PcdGet32 (PcdMaxVariableSize) bytes for the others.
3212 if ((Attributes
& EFI_VARIABLE_HARDWARE_ERROR_RECORD
) == EFI_VARIABLE_HARDWARE_ERROR_RECORD
) {
3213 if (StrSize (VariableName
) + PayloadSize
> PcdGet32 (PcdMaxHardwareErrorVariableSize
) - sizeof (VARIABLE_HEADER
)) {
3214 return EFI_INVALID_PARAMETER
;
3216 if (!IsHwErrRecVariable(VariableName
, VendorGuid
)) {
3217 return EFI_INVALID_PARAMETER
;
3221 // The size of the VariableName, including the Unicode Null in bytes plus
3222 // the DataSize is limited to maximum size of PcdGet32 (PcdMaxVariableSize) bytes.
3224 if (StrSize (VariableName
) + PayloadSize
> PcdGet32 (PcdMaxVariableSize
) - sizeof (VARIABLE_HEADER
)) {
3225 return EFI_INVALID_PARAMETER
;
3229 AcquireLockOnlyAtBootTime(&mVariableModuleGlobal
->VariableGlobal
.VariableServicesLock
);
3232 // Consider reentrant in MCA/INIT/NMI. It needs be reupdated.
3234 if (1 < InterlockedIncrement (&mVariableModuleGlobal
->VariableGlobal
.ReentrantState
)) {
3235 Point
= mVariableModuleGlobal
->VariableGlobal
.NonVolatileVariableBase
;
3237 // Parse non-volatile variable data and get last variable offset.
3239 NextVariable
= GetStartPointer ((VARIABLE_STORE_HEADER
*) (UINTN
) Point
);
3240 while (IsValidVariableHeader (NextVariable
, GetEndPointer ((VARIABLE_STORE_HEADER
*) (UINTN
) Point
))) {
3241 NextVariable
= GetNextVariablePtr (NextVariable
);
3243 mVariableModuleGlobal
->NonVolatileLastVariableOffset
= (UINTN
) NextVariable
- (UINTN
) Point
;
3246 if (mEndOfDxe
&& mEnableLocking
) {
3248 // Treat the variables listed in the forbidden variable list as read-only after leaving DXE phase.
3250 for ( Link
= GetFirstNode (&mLockedVariableList
)
3251 ; !IsNull (&mLockedVariableList
, Link
)
3252 ; Link
= GetNextNode (&mLockedVariableList
, Link
)
3254 Entry
= BASE_CR (Link
, VARIABLE_ENTRY
, Link
);
3255 Name
= (CHAR16
*) ((UINTN
) Entry
+ sizeof (*Entry
));
3256 if (CompareGuid (&Entry
->Guid
, VendorGuid
) && (StrCmp (Name
, VariableName
) == 0)) {
3257 Status
= EFI_WRITE_PROTECTED
;
3258 DEBUG ((EFI_D_INFO
, "[Variable]: Changing readonly variable after leaving DXE phase - %g:%s\n", VendorGuid
, VariableName
));
3264 Status
= InternalVarCheckSetVariableCheck (VariableName
, VendorGuid
, Attributes
, PayloadSize
, (VOID
*) ((UINTN
) Data
+ DataSize
- PayloadSize
));
3265 if (EFI_ERROR (Status
)) {
3270 // Check whether the input variable is already existed.
3272 Status
= FindVariable (VariableName
, VendorGuid
, &Variable
, &mVariableModuleGlobal
->VariableGlobal
, TRUE
);
3273 if (!EFI_ERROR (Status
)) {
3274 if (((Variable
.CurrPtr
->Attributes
& EFI_VARIABLE_RUNTIME_ACCESS
) == 0) && AtRuntime ()) {
3275 Status
= EFI_WRITE_PROTECTED
;
3278 if (Attributes
!= 0 && (Attributes
& (~EFI_VARIABLE_APPEND_WRITE
)) != Variable
.CurrPtr
->Attributes
) {
3280 // If a preexisting variable is rewritten with different attributes, SetVariable() shall not
3281 // modify the variable and shall return EFI_INVALID_PARAMETER. Two exceptions to this rule:
3282 // 1. No access attributes specified
3283 // 2. The only attribute differing is EFI_VARIABLE_APPEND_WRITE
3285 Status
= EFI_INVALID_PARAMETER
;
3286 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
));
3291 if (!FeaturePcdGet (PcdUefiVariableDefaultLangDeprecate
)) {
3293 // Hook the operation of setting PlatformLangCodes/PlatformLang and LangCodes/Lang.
3295 Status
= AutoUpdateLangVariable (VariableName
, Data
, DataSize
);
3296 if (EFI_ERROR (Status
)) {
3298 // The auto update operation failed, directly return to avoid inconsistency between PlatformLang and Lang.
3305 // Process PK, KEK, Sigdb seperately.
3307 if (CompareGuid (VendorGuid
, &gEfiGlobalVariableGuid
) && (StrCmp (VariableName
, EFI_PLATFORM_KEY_NAME
) == 0)){
3308 Status
= ProcessVarWithPk (VariableName
, VendorGuid
, Data
, DataSize
, &Variable
, Attributes
, TRUE
);
3309 } else if (CompareGuid (VendorGuid
, &gEfiGlobalVariableGuid
) && (StrCmp (VariableName
, EFI_KEY_EXCHANGE_KEY_NAME
) == 0)) {
3310 Status
= ProcessVarWithPk (VariableName
, VendorGuid
, Data
, DataSize
, &Variable
, Attributes
, FALSE
);
3311 } else if (CompareGuid (VendorGuid
, &gEfiImageSecurityDatabaseGuid
) &&
3312 ((StrCmp (VariableName
, EFI_IMAGE_SECURITY_DATABASE
) == 0) ||
3313 (StrCmp (VariableName
, EFI_IMAGE_SECURITY_DATABASE1
) == 0) ||
3314 (StrCmp (VariableName
, EFI_IMAGE_SECURITY_DATABASE2
) == 0)
3317 Status
= ProcessVarWithPk (VariableName
, VendorGuid
, Data
, DataSize
, &Variable
, Attributes
, FALSE
);
3318 if (EFI_ERROR (Status
)) {
3319 Status
= ProcessVarWithKek (VariableName
, VendorGuid
, Data
, DataSize
, &Variable
, Attributes
);
3322 Status
= ProcessVariable (VariableName
, VendorGuid
, Data
, DataSize
, &Variable
, Attributes
);
3326 InterlockedDecrement (&mVariableModuleGlobal
->VariableGlobal
.ReentrantState
);
3327 ReleaseLockOnlyAtBootTime (&mVariableModuleGlobal
->VariableGlobal
.VariableServicesLock
);
3329 if (!AtRuntime ()) {
3330 if (!EFI_ERROR (Status
)) {
3343 This code returns information about the EFI variables.
3345 Caution: This function may receive untrusted input.
3346 This function may be invoked in SMM mode. This function will do basic validation, before parse the data.
3348 @param Attributes Attributes bitmask to specify the type of variables
3349 on which to return information.
3350 @param MaximumVariableStorageSize Pointer to the maximum size of the storage space available
3351 for the EFI variables associated with the attributes specified.
3352 @param RemainingVariableStorageSize Pointer to the remaining size of the storage space available
3353 for EFI variables associated with the attributes specified.
3354 @param MaximumVariableSize Pointer to the maximum size of an individual EFI variables
3355 associated with the attributes specified.
3357 @return EFI_SUCCESS Query successfully.
3362 VariableServiceQueryVariableInfoInternal (
3363 IN UINT32 Attributes
,
3364 OUT UINT64
*MaximumVariableStorageSize
,
3365 OUT UINT64
*RemainingVariableStorageSize
,
3366 OUT UINT64
*MaximumVariableSize
3369 VARIABLE_HEADER
*Variable
;
3370 VARIABLE_HEADER
*NextVariable
;
3371 UINT64 VariableSize
;
3372 VARIABLE_STORE_HEADER
*VariableStoreHeader
;
3373 UINT64 CommonVariableTotalSize
;
3374 UINT64 HwErrVariableTotalSize
;
3376 VARIABLE_POINTER_TRACK VariablePtrTrack
;
3378 CommonVariableTotalSize
= 0;
3379 HwErrVariableTotalSize
= 0;
3381 if((Attributes
& EFI_VARIABLE_NON_VOLATILE
) == 0) {
3383 // Query is Volatile related.
3385 VariableStoreHeader
= (VARIABLE_STORE_HEADER
*) ((UINTN
) mVariableModuleGlobal
->VariableGlobal
.VolatileVariableBase
);
3388 // Query is Non-Volatile related.
3390 VariableStoreHeader
= mNvVariableCache
;
3394 // Now let's fill *MaximumVariableStorageSize *RemainingVariableStorageSize
3395 // with the storage size (excluding the storage header size).
3397 *MaximumVariableStorageSize
= VariableStoreHeader
->Size
- sizeof (VARIABLE_STORE_HEADER
);
3400 // Harware error record variable needs larger size.
3402 if ((Attributes
& (EFI_VARIABLE_NON_VOLATILE
| EFI_VARIABLE_HARDWARE_ERROR_RECORD
)) == (EFI_VARIABLE_NON_VOLATILE
| EFI_VARIABLE_HARDWARE_ERROR_RECORD
)) {
3403 *MaximumVariableStorageSize
= PcdGet32 (PcdHwErrStorageSize
);
3404 *MaximumVariableSize
= PcdGet32 (PcdMaxHardwareErrorVariableSize
) - sizeof (VARIABLE_HEADER
);
3406 if ((Attributes
& EFI_VARIABLE_NON_VOLATILE
) != 0) {
3408 *MaximumVariableStorageSize
= mVariableModuleGlobal
->CommonRuntimeVariableSpace
;
3410 *MaximumVariableStorageSize
= mVariableModuleGlobal
->CommonVariableSpace
;
3415 // Let *MaximumVariableSize be PcdGet32 (PcdMaxVariableSize) with the exception of the variable header size.
3417 *MaximumVariableSize
= PcdGet32 (PcdMaxVariableSize
) - sizeof (VARIABLE_HEADER
);
3421 // Point to the starting address of the variables.
3423 Variable
= GetStartPointer (VariableStoreHeader
);
3426 // Now walk through the related variable store.
3428 while (IsValidVariableHeader (Variable
, GetEndPointer (VariableStoreHeader
))) {
3429 NextVariable
= GetNextVariablePtr (Variable
);
3430 VariableSize
= (UINT64
) (UINTN
) NextVariable
- (UINT64
) (UINTN
) Variable
;
3434 // We don't take the state of the variables in mind
3435 // when calculating RemainingVariableStorageSize,
3436 // since the space occupied by variables not marked with
3437 // VAR_ADDED is not allowed to be reclaimed in Runtime.
3439 if ((Variable
->Attributes
& EFI_VARIABLE_HARDWARE_ERROR_RECORD
) == EFI_VARIABLE_HARDWARE_ERROR_RECORD
) {
3440 HwErrVariableTotalSize
+= VariableSize
;
3442 CommonVariableTotalSize
+= VariableSize
;
3446 // Only care about Variables with State VAR_ADDED, because
3447 // the space not marked as VAR_ADDED is reclaimable now.
3449 if (Variable
->State
== VAR_ADDED
) {
3450 if ((Variable
->Attributes
& EFI_VARIABLE_HARDWARE_ERROR_RECORD
) == EFI_VARIABLE_HARDWARE_ERROR_RECORD
) {
3451 HwErrVariableTotalSize
+= VariableSize
;
3453 CommonVariableTotalSize
+= VariableSize
;
3455 } else if (Variable
->State
== (VAR_IN_DELETED_TRANSITION
& VAR_ADDED
)) {
3457 // If it is a IN_DELETED_TRANSITION variable,
3458 // and there is not also a same ADDED one at the same time,
3459 // this IN_DELETED_TRANSITION variable is valid.
3461 VariablePtrTrack
.StartPtr
= GetStartPointer (VariableStoreHeader
);
3462 VariablePtrTrack
.EndPtr
= GetEndPointer (VariableStoreHeader
);
3463 Status
= FindVariableEx (
3464 GetVariableNamePtr (Variable
),
3465 &Variable
->VendorGuid
,
3469 if (!EFI_ERROR (Status
) && VariablePtrTrack
.CurrPtr
->State
!= VAR_ADDED
) {
3470 if ((Variable
->Attributes
& EFI_VARIABLE_HARDWARE_ERROR_RECORD
) == EFI_VARIABLE_HARDWARE_ERROR_RECORD
) {
3471 HwErrVariableTotalSize
+= VariableSize
;
3473 CommonVariableTotalSize
+= VariableSize
;
3480 // Go to the next one.
3482 Variable
= NextVariable
;
3485 if ((Attributes
& EFI_VARIABLE_HARDWARE_ERROR_RECORD
) == EFI_VARIABLE_HARDWARE_ERROR_RECORD
){
3486 *RemainingVariableStorageSize
= *MaximumVariableStorageSize
- HwErrVariableTotalSize
;
3488 if (*MaximumVariableStorageSize
< CommonVariableTotalSize
) {
3489 *RemainingVariableStorageSize
= 0;
3491 *RemainingVariableStorageSize
= *MaximumVariableStorageSize
- CommonVariableTotalSize
;
3495 if (*RemainingVariableStorageSize
< sizeof (VARIABLE_HEADER
)) {
3496 *MaximumVariableSize
= 0;
3497 } else if ((*RemainingVariableStorageSize
- sizeof (VARIABLE_HEADER
)) < *MaximumVariableSize
) {
3498 *MaximumVariableSize
= *RemainingVariableStorageSize
- sizeof (VARIABLE_HEADER
);
3506 This code returns information about the EFI variables.
3508 Caution: This function may receive untrusted input.
3509 This function may be invoked in SMM mode. This function will do basic validation, before parse the data.
3511 @param Attributes Attributes bitmask to specify the type of variables
3512 on which to return information.
3513 @param MaximumVariableStorageSize Pointer to the maximum size of the storage space available
3514 for the EFI variables associated with the attributes specified.
3515 @param RemainingVariableStorageSize Pointer to the remaining size of the storage space available
3516 for EFI variables associated with the attributes specified.
3517 @param MaximumVariableSize Pointer to the maximum size of an individual EFI variables
3518 associated with the attributes specified.
3520 @return EFI_INVALID_PARAMETER An invalid combination of attribute bits was supplied.
3521 @return EFI_SUCCESS Query successfully.
3522 @return EFI_UNSUPPORTED The attribute is not supported on this platform.
3527 VariableServiceQueryVariableInfo (
3528 IN UINT32 Attributes
,
3529 OUT UINT64
*MaximumVariableStorageSize
,
3530 OUT UINT64
*RemainingVariableStorageSize
,
3531 OUT UINT64
*MaximumVariableSize
3536 if(MaximumVariableStorageSize
== NULL
|| RemainingVariableStorageSize
== NULL
|| MaximumVariableSize
== NULL
|| Attributes
== 0) {
3537 return EFI_INVALID_PARAMETER
;
3540 if ((Attributes
& VARIABLE_ATTRIBUTE_NV_BS_RT_AT_HR_AW
) == 0) {
3542 // Make sure the Attributes combination is supported by the platform.
3544 return EFI_UNSUPPORTED
;
3545 } else if ((Attributes
& (EFI_VARIABLE_RUNTIME_ACCESS
| EFI_VARIABLE_BOOTSERVICE_ACCESS
)) == EFI_VARIABLE_RUNTIME_ACCESS
) {
3547 // Make sure if runtime bit is set, boot service bit is set also.
3549 return EFI_INVALID_PARAMETER
;
3550 } else if (AtRuntime () && ((Attributes
& EFI_VARIABLE_RUNTIME_ACCESS
) == 0)) {
3552 // Make sure RT Attribute is set if we are in Runtime phase.
3554 return EFI_INVALID_PARAMETER
;
3555 } else if ((Attributes
& (EFI_VARIABLE_NON_VOLATILE
| EFI_VARIABLE_HARDWARE_ERROR_RECORD
)) == EFI_VARIABLE_HARDWARE_ERROR_RECORD
) {
3557 // Make sure Hw Attribute is set with NV.
3559 return EFI_INVALID_PARAMETER
;
3562 AcquireLockOnlyAtBootTime(&mVariableModuleGlobal
->VariableGlobal
.VariableServicesLock
);
3564 Status
= VariableServiceQueryVariableInfoInternal (
3566 MaximumVariableStorageSize
,
3567 RemainingVariableStorageSize
,
3571 ReleaseLockOnlyAtBootTime (&mVariableModuleGlobal
->VariableGlobal
.VariableServicesLock
);
3576 This function reclaims variable storage if free size is below the threshold.
3578 Caution: This function may be invoked at SMM mode.
3579 Care must be taken to make sure not security issue.
3588 UINTN RemainingCommonRuntimeVariableSpace
;
3589 UINTN RemainingHwErrVariableSpace
;
3591 Status
= EFI_SUCCESS
;
3593 if (mVariableModuleGlobal
->CommonRuntimeVariableSpace
< mVariableModuleGlobal
->CommonVariableTotalSize
) {
3594 RemainingCommonRuntimeVariableSpace
= 0;
3596 RemainingCommonRuntimeVariableSpace
= mVariableModuleGlobal
->CommonRuntimeVariableSpace
- mVariableModuleGlobal
->CommonVariableTotalSize
;
3599 RemainingHwErrVariableSpace
= PcdGet32 (PcdHwErrStorageSize
) - mVariableModuleGlobal
->HwErrVariableTotalSize
;
3601 // Check if the free area is below a threshold.
3603 if ((RemainingCommonRuntimeVariableSpace
< PcdGet32 (PcdMaxVariableSize
))
3604 || ((PcdGet32 (PcdHwErrStorageSize
) != 0) &&
3605 (RemainingHwErrVariableSpace
< PcdGet32 (PcdMaxHardwareErrorVariableSize
)))){
3607 mVariableModuleGlobal
->VariableGlobal
.NonVolatileVariableBase
,
3608 &mVariableModuleGlobal
->NonVolatileLastVariableOffset
,
3615 ASSERT_EFI_ERROR (Status
);
3620 Init non-volatile variable store.
3622 @retval EFI_SUCCESS Function successfully executed.
3623 @retval EFI_OUT_OF_RESOURCES Fail to allocate enough memory resource.
3624 @retval EFI_VOLUME_CORRUPTED Variable Store or Firmware Volume for Variable Store is corrupted.
3628 InitNonVolatileVariableStore (
3632 EFI_FIRMWARE_VOLUME_HEADER
*FvHeader
;
3633 VARIABLE_HEADER
*Variable
;
3634 VARIABLE_HEADER
*NextVariable
;
3635 EFI_PHYSICAL_ADDRESS VariableStoreBase
;
3636 UINT64 VariableStoreLength
;
3638 EFI_HOB_GUID_TYPE
*GuidHob
;
3639 EFI_PHYSICAL_ADDRESS NvStorageBase
;
3640 UINT8
*NvStorageData
;
3641 UINT32 NvStorageSize
;
3642 FAULT_TOLERANT_WRITE_LAST_WRITE_DATA
*FtwLastWriteData
;
3643 UINT32 BackUpOffset
;
3645 UINT32 HwErrStorageSize
;
3646 UINT32 MaxUserNvVariableSpaceSize
;
3647 UINT32 BoottimeReservedNvVariableSpaceSize
;
3649 mVariableModuleGlobal
->FvbInstance
= NULL
;
3652 // Allocate runtime memory used for a memory copy of the FLASH region.
3653 // Keep the memory and the FLASH in sync as updates occur.
3655 NvStorageSize
= PcdGet32 (PcdFlashNvStorageVariableSize
);
3656 NvStorageData
= AllocateRuntimeZeroPool (NvStorageSize
);
3657 if (NvStorageData
== NULL
) {
3658 return EFI_OUT_OF_RESOURCES
;
3661 NvStorageBase
= (EFI_PHYSICAL_ADDRESS
) PcdGet64 (PcdFlashNvStorageVariableBase64
);
3662 if (NvStorageBase
== 0) {
3663 NvStorageBase
= (EFI_PHYSICAL_ADDRESS
) PcdGet32 (PcdFlashNvStorageVariableBase
);
3666 // Copy NV storage data to the memory buffer.
3668 CopyMem (NvStorageData
, (UINT8
*) (UINTN
) NvStorageBase
, NvStorageSize
);
3671 // Check the FTW last write data hob.
3673 GuidHob
= GetFirstGuidHob (&gEdkiiFaultTolerantWriteGuid
);
3674 if (GuidHob
!= NULL
) {
3675 FtwLastWriteData
= (FAULT_TOLERANT_WRITE_LAST_WRITE_DATA
*) GET_GUID_HOB_DATA (GuidHob
);
3676 if (FtwLastWriteData
->TargetAddress
== NvStorageBase
) {
3677 DEBUG ((EFI_D_INFO
, "Variable: NV storage is backed up in spare block: 0x%x\n", (UINTN
) FtwLastWriteData
->SpareAddress
));
3679 // Copy the backed up NV storage data to the memory buffer from spare block.
3681 CopyMem (NvStorageData
, (UINT8
*) (UINTN
) (FtwLastWriteData
->SpareAddress
), NvStorageSize
);
3682 } else if ((FtwLastWriteData
->TargetAddress
> NvStorageBase
) &&
3683 (FtwLastWriteData
->TargetAddress
< (NvStorageBase
+ NvStorageSize
))) {
3685 // Flash NV storage from the Offset is backed up in spare block.
3687 BackUpOffset
= (UINT32
) (FtwLastWriteData
->TargetAddress
- NvStorageBase
);
3688 BackUpSize
= NvStorageSize
- BackUpOffset
;
3689 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
));
3691 // Copy the partial backed up NV storage data to the memory buffer from spare block.
3693 CopyMem (NvStorageData
+ BackUpOffset
, (UINT8
*) (UINTN
) FtwLastWriteData
->SpareAddress
, BackUpSize
);
3697 FvHeader
= (EFI_FIRMWARE_VOLUME_HEADER
*) NvStorageData
;
3700 // Check if the Firmware Volume is not corrupted
3702 if ((FvHeader
->Signature
!= EFI_FVH_SIGNATURE
) || (!CompareGuid (&gEfiSystemNvDataFvGuid
, &FvHeader
->FileSystemGuid
))) {
3703 FreePool (NvStorageData
);
3704 DEBUG ((EFI_D_ERROR
, "Firmware Volume for Variable Store is corrupted\n"));
3705 return EFI_VOLUME_CORRUPTED
;
3708 VariableStoreBase
= (EFI_PHYSICAL_ADDRESS
) ((UINTN
) FvHeader
+ FvHeader
->HeaderLength
);
3709 VariableStoreLength
= (UINT64
) (NvStorageSize
- FvHeader
->HeaderLength
);
3711 mVariableModuleGlobal
->VariableGlobal
.NonVolatileVariableBase
= VariableStoreBase
;
3712 mNvVariableCache
= (VARIABLE_STORE_HEADER
*) (UINTN
) VariableStoreBase
;
3713 if (GetVariableStoreStatus (mNvVariableCache
) != EfiValid
) {
3714 FreePool (NvStorageData
);
3715 DEBUG((EFI_D_ERROR
, "Variable Store header is corrupted\n"));
3716 return EFI_VOLUME_CORRUPTED
;
3718 ASSERT(mNvVariableCache
->Size
== VariableStoreLength
);
3721 ASSERT (sizeof (VARIABLE_STORE_HEADER
) <= VariableStoreLength
);
3723 HwErrStorageSize
= PcdGet32 (PcdHwErrStorageSize
);
3724 MaxUserNvVariableSpaceSize
= PcdGet32 (PcdMaxUserNvVariableSpaceSize
);
3725 BoottimeReservedNvVariableSpaceSize
= PcdGet32 (PcdBoottimeReservedNvVariableSpaceSize
);
3728 // Note that in EdkII variable driver implementation, Hardware Error Record type variable
3729 // is stored with common variable in the same NV region. So the platform integrator should
3730 // ensure that the value of PcdHwErrStorageSize is less than the value of
3731 // VariableStoreLength - sizeof (VARIABLE_STORE_HEADER)).
3733 ASSERT (HwErrStorageSize
< (VariableStoreLength
- sizeof (VARIABLE_STORE_HEADER
)));
3735 // Ensure that the value of PcdMaxUserNvVariableSpaceSize is less than the value of
3736 // VariableStoreLength - sizeof (VARIABLE_STORE_HEADER)) - PcdGet32 (PcdHwErrStorageSize).
3738 ASSERT (MaxUserNvVariableSpaceSize
< (VariableStoreLength
- sizeof (VARIABLE_STORE_HEADER
) - HwErrStorageSize
));
3740 // Ensure that the value of PcdBoottimeReservedNvVariableSpaceSize is less than the value of
3741 // VariableStoreLength - sizeof (VARIABLE_STORE_HEADER)) - PcdGet32 (PcdHwErrStorageSize).
3743 ASSERT (BoottimeReservedNvVariableSpaceSize
< (VariableStoreLength
- sizeof (VARIABLE_STORE_HEADER
) - HwErrStorageSize
));
3745 mVariableModuleGlobal
->CommonVariableSpace
= ((UINTN
) VariableStoreLength
- sizeof (VARIABLE_STORE_HEADER
) - HwErrStorageSize
);
3746 mVariableModuleGlobal
->CommonMaxUserVariableSpace
= ((MaxUserNvVariableSpaceSize
!= 0) ? MaxUserNvVariableSpaceSize
: mVariableModuleGlobal
->CommonVariableSpace
);
3747 mVariableModuleGlobal
->CommonRuntimeVariableSpace
= mVariableModuleGlobal
->CommonVariableSpace
- BoottimeReservedNvVariableSpaceSize
;
3749 DEBUG ((EFI_D_INFO
, "Variable driver common space: 0x%x 0x%x 0x%x\n", mVariableModuleGlobal
->CommonVariableSpace
, mVariableModuleGlobal
->CommonMaxUserVariableSpace
, mVariableModuleGlobal
->CommonRuntimeVariableSpace
));
3752 // The max variable or hardware error variable size should be < variable store size.
3754 ASSERT(MAX (PcdGet32 (PcdMaxVariableSize
), PcdGet32 (PcdMaxHardwareErrorVariableSize
)) < VariableStoreLength
);
3757 // Parse non-volatile variable data and get last variable offset.
3759 Variable
= GetStartPointer ((VARIABLE_STORE_HEADER
*)(UINTN
)VariableStoreBase
);
3760 while (IsValidVariableHeader (Variable
, GetEndPointer ((VARIABLE_STORE_HEADER
*)(UINTN
)VariableStoreBase
))) {
3761 NextVariable
= GetNextVariablePtr (Variable
);
3762 VariableSize
= (UINTN
) NextVariable
- (UINTN
) Variable
;
3763 if ((Variable
->Attributes
& (EFI_VARIABLE_NON_VOLATILE
| EFI_VARIABLE_HARDWARE_ERROR_RECORD
)) == (EFI_VARIABLE_NON_VOLATILE
| EFI_VARIABLE_HARDWARE_ERROR_RECORD
)) {
3764 mVariableModuleGlobal
->HwErrVariableTotalSize
+= VariableSize
;
3766 mVariableModuleGlobal
->CommonVariableTotalSize
+= VariableSize
;
3769 Variable
= NextVariable
;
3771 mVariableModuleGlobal
->NonVolatileLastVariableOffset
= (UINTN
) Variable
- (UINTN
) VariableStoreBase
;
3777 Flush the HOB variable to flash.
3779 @param[in] VariableName Name of variable has been updated or deleted.
3780 @param[in] VendorGuid Guid of variable has been updated or deleted.
3784 FlushHobVariableToFlash (
3785 IN CHAR16
*VariableName
,
3786 IN EFI_GUID
*VendorGuid
3790 VARIABLE_STORE_HEADER
*VariableStoreHeader
;
3791 VARIABLE_HEADER
*Variable
;
3798 // Flush the HOB variable to flash.
3800 if (mVariableModuleGlobal
->VariableGlobal
.HobVariableBase
!= 0) {
3801 VariableStoreHeader
= (VARIABLE_STORE_HEADER
*) (UINTN
) mVariableModuleGlobal
->VariableGlobal
.HobVariableBase
;
3803 // Set HobVariableBase to 0, it can avoid SetVariable to call back.
3805 mVariableModuleGlobal
->VariableGlobal
.HobVariableBase
= 0;
3806 for ( Variable
= GetStartPointer (VariableStoreHeader
)
3807 ; IsValidVariableHeader (Variable
, GetEndPointer (VariableStoreHeader
))
3808 ; Variable
= GetNextVariablePtr (Variable
)
3810 if (Variable
->State
!= VAR_ADDED
) {
3812 // The HOB variable has been set to DELETED state in local.
3816 ASSERT ((Variable
->Attributes
& EFI_VARIABLE_NON_VOLATILE
) != 0);
3817 if (VendorGuid
== NULL
|| VariableName
== NULL
||
3818 !CompareGuid (VendorGuid
, &Variable
->VendorGuid
) ||
3819 StrCmp (VariableName
, GetVariableNamePtr (Variable
)) != 0) {
3820 VariableData
= GetVariableDataPtr (Variable
);
3821 Status
= VariableServiceSetVariable (
3822 GetVariableNamePtr (Variable
),
3823 &Variable
->VendorGuid
,
3824 Variable
->Attributes
,
3828 DEBUG ((EFI_D_INFO
, "Variable driver flush the HOB variable to flash: %g %s %r\n", &Variable
->VendorGuid
, GetVariableNamePtr (Variable
), Status
));
3831 // The updated or deleted variable is matched with the HOB variable.
3832 // Don't break here because we will try to set other HOB variables
3833 // since this variable could be set successfully.
3835 Status
= EFI_SUCCESS
;
3837 if (!EFI_ERROR (Status
)) {
3839 // If set variable successful, or the updated or deleted variable is matched with the HOB variable,
3840 // set the HOB variable to DELETED state in local.
3842 DEBUG ((EFI_D_INFO
, "Variable driver set the HOB variable to DELETED state in local: %g %s\n", &Variable
->VendorGuid
, GetVariableNamePtr (Variable
)));
3843 Variable
->State
&= VAR_DELETED
;
3850 // We still have HOB variable(s) not flushed in flash.
3852 mVariableModuleGlobal
->VariableGlobal
.HobVariableBase
= (EFI_PHYSICAL_ADDRESS
) (UINTN
) VariableStoreHeader
;
3855 // All HOB variables have been flushed in flash.
3857 DEBUG ((EFI_D_INFO
, "Variable driver: all HOB variables have been flushed in flash.\n"));
3858 if (!AtRuntime ()) {
3859 FreePool ((VOID
*) VariableStoreHeader
);
3867 Initializes variable write service after FTW was ready.
3869 @retval EFI_SUCCESS Function successfully executed.
3870 @retval Others Fail to initialize the variable service.
3874 VariableWriteServiceInitialize (
3879 VARIABLE_STORE_HEADER
*VariableStoreHeader
;
3882 EFI_PHYSICAL_ADDRESS VariableStoreBase
;
3883 EFI_PHYSICAL_ADDRESS NvStorageBase
;
3885 NvStorageBase
= (EFI_PHYSICAL_ADDRESS
) PcdGet64 (PcdFlashNvStorageVariableBase64
);
3886 if (NvStorageBase
== 0) {
3887 NvStorageBase
= (EFI_PHYSICAL_ADDRESS
) PcdGet32 (PcdFlashNvStorageVariableBase
);
3889 VariableStoreBase
= NvStorageBase
+ (((EFI_FIRMWARE_VOLUME_HEADER
*)(UINTN
)(NvStorageBase
))->HeaderLength
);
3892 // Let NonVolatileVariableBase point to flash variable store base directly after FTW ready.
3894 mVariableModuleGlobal
->VariableGlobal
.NonVolatileVariableBase
= VariableStoreBase
;
3895 VariableStoreHeader
= (VARIABLE_STORE_HEADER
*)(UINTN
)VariableStoreBase
;
3898 // Check if the free area is really free.
3900 for (Index
= mVariableModuleGlobal
->NonVolatileLastVariableOffset
; Index
< VariableStoreHeader
->Size
; Index
++) {
3901 Data
= ((UINT8
*) mNvVariableCache
)[Index
];
3904 // There must be something wrong in variable store, do reclaim operation.
3907 mVariableModuleGlobal
->VariableGlobal
.NonVolatileVariableBase
,
3908 &mVariableModuleGlobal
->NonVolatileLastVariableOffset
,
3915 if (EFI_ERROR (Status
)) {
3922 FlushHobVariableToFlash (NULL
, NULL
);
3925 // Authenticated variable initialize.
3927 Status
= AutenticatedVariableServiceInitialize ();
3934 Initializes variable store area for non-volatile and volatile variable.
3936 @retval EFI_SUCCESS Function successfully executed.
3937 @retval EFI_OUT_OF_RESOURCES Fail to allocate enough memory resource.
3941 VariableCommonInitialize (
3946 VARIABLE_STORE_HEADER
*VolatileVariableStore
;
3947 VARIABLE_STORE_HEADER
*VariableStoreHeader
;
3948 UINT64 VariableStoreLength
;
3950 EFI_HOB_GUID_TYPE
*GuidHob
;
3953 // Allocate runtime memory for variable driver global structure.
3955 mVariableModuleGlobal
= AllocateRuntimeZeroPool (sizeof (VARIABLE_MODULE_GLOBAL
));
3956 if (mVariableModuleGlobal
== NULL
) {
3957 return EFI_OUT_OF_RESOURCES
;
3960 InitializeLock (&mVariableModuleGlobal
->VariableGlobal
.VariableServicesLock
, TPL_NOTIFY
);
3963 // Get HOB variable store.
3965 GuidHob
= GetFirstGuidHob (&gEfiAuthenticatedVariableGuid
);
3966 if (GuidHob
!= NULL
) {
3967 VariableStoreHeader
= GET_GUID_HOB_DATA (GuidHob
);
3968 VariableStoreLength
= (UINT64
) (GuidHob
->Header
.HobLength
- sizeof (EFI_HOB_GUID_TYPE
));
3969 if (GetVariableStoreStatus (VariableStoreHeader
) == EfiValid
) {
3970 mVariableModuleGlobal
->VariableGlobal
.HobVariableBase
= (EFI_PHYSICAL_ADDRESS
) (UINTN
) AllocateRuntimeCopyPool ((UINTN
) VariableStoreLength
, (VOID
*) VariableStoreHeader
);
3971 if (mVariableModuleGlobal
->VariableGlobal
.HobVariableBase
== 0) {
3972 FreePool (mVariableModuleGlobal
);
3973 return EFI_OUT_OF_RESOURCES
;
3976 DEBUG ((EFI_D_ERROR
, "HOB Variable Store header is corrupted!\n"));
3981 // Allocate memory for volatile variable store, note that there is a scratch space to store scratch data.
3983 ScratchSize
= MAX (PcdGet32 (PcdMaxVariableSize
), PcdGet32 (PcdMaxHardwareErrorVariableSize
));
3984 VolatileVariableStore
= AllocateRuntimePool (PcdGet32 (PcdVariableStoreSize
) + ScratchSize
);
3985 if (VolatileVariableStore
== NULL
) {
3986 if (mVariableModuleGlobal
->VariableGlobal
.HobVariableBase
!= 0) {
3987 FreePool ((VOID
*) (UINTN
) mVariableModuleGlobal
->VariableGlobal
.HobVariableBase
);
3989 FreePool (mVariableModuleGlobal
);
3990 return EFI_OUT_OF_RESOURCES
;
3993 SetMem (VolatileVariableStore
, PcdGet32 (PcdVariableStoreSize
) + ScratchSize
, 0xff);
3996 // Initialize Variable Specific Data.
3998 mVariableModuleGlobal
->VariableGlobal
.VolatileVariableBase
= (EFI_PHYSICAL_ADDRESS
) (UINTN
) VolatileVariableStore
;
3999 mVariableModuleGlobal
->VolatileLastVariableOffset
= (UINTN
) GetStartPointer (VolatileVariableStore
) - (UINTN
) VolatileVariableStore
;
4001 CopyGuid (&VolatileVariableStore
->Signature
, &gEfiAuthenticatedVariableGuid
);
4002 VolatileVariableStore
->Size
= PcdGet32 (PcdVariableStoreSize
);
4003 VolatileVariableStore
->Format
= VARIABLE_STORE_FORMATTED
;
4004 VolatileVariableStore
->State
= VARIABLE_STORE_HEALTHY
;
4005 VolatileVariableStore
->Reserved
= 0;
4006 VolatileVariableStore
->Reserved1
= 0;
4009 // Init non-volatile variable store.
4011 Status
= InitNonVolatileVariableStore ();
4012 if (EFI_ERROR (Status
)) {
4013 if (mVariableModuleGlobal
->VariableGlobal
.HobVariableBase
!= 0) {
4014 FreePool ((VOID
*) (UINTN
) mVariableModuleGlobal
->VariableGlobal
.HobVariableBase
);
4016 FreePool (mVariableModuleGlobal
);
4017 FreePool (VolatileVariableStore
);
4025 Get the proper fvb handle and/or fvb protocol by the given Flash address.
4027 @param[in] Address The Flash address.
4028 @param[out] FvbHandle In output, if it is not NULL, it points to the proper FVB handle.
4029 @param[out] FvbProtocol In output, if it is not NULL, it points to the proper FVB protocol.
4033 GetFvbInfoByAddress (
4034 IN EFI_PHYSICAL_ADDRESS Address
,
4035 OUT EFI_HANDLE
*FvbHandle OPTIONAL
,
4036 OUT EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
**FvbProtocol OPTIONAL
4040 EFI_HANDLE
*HandleBuffer
;
4043 EFI_PHYSICAL_ADDRESS FvbBaseAddress
;
4044 EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*Fvb
;
4045 EFI_FVB_ATTRIBUTES_2 Attributes
;
4047 UINTN NumberOfBlocks
;
4049 HandleBuffer
= NULL
;
4051 // Get all FVB handles.
4053 Status
= GetFvbCountAndBuffer (&HandleCount
, &HandleBuffer
);
4054 if (EFI_ERROR (Status
)) {
4055 return EFI_NOT_FOUND
;
4059 // Get the FVB to access variable store.
4062 for (Index
= 0; Index
< HandleCount
; Index
+= 1, Status
= EFI_NOT_FOUND
, Fvb
= NULL
) {
4063 Status
= GetFvbByHandle (HandleBuffer
[Index
], &Fvb
);
4064 if (EFI_ERROR (Status
)) {
4065 Status
= EFI_NOT_FOUND
;
4070 // Ensure this FVB protocol supported Write operation.
4072 Status
= Fvb
->GetAttributes (Fvb
, &Attributes
);
4073 if (EFI_ERROR (Status
) || ((Attributes
& EFI_FVB2_WRITE_STATUS
) == 0)) {
4078 // Compare the address and select the right one.
4080 Status
= Fvb
->GetPhysicalAddress (Fvb
, &FvbBaseAddress
);
4081 if (EFI_ERROR (Status
)) {
4086 // Assume one FVB has one type of BlockSize.
4088 Status
= Fvb
->GetBlockSize (Fvb
, 0, &BlockSize
, &NumberOfBlocks
);
4089 if (EFI_ERROR (Status
)) {
4093 if ((Address
>= FvbBaseAddress
) && (Address
< (FvbBaseAddress
+ BlockSize
* NumberOfBlocks
))) {
4094 if (FvbHandle
!= NULL
) {
4095 *FvbHandle
= HandleBuffer
[Index
];
4097 if (FvbProtocol
!= NULL
) {
4100 Status
= EFI_SUCCESS
;
4104 FreePool (HandleBuffer
);
4107 Status
= EFI_NOT_FOUND
;