2 The common variable operation routines shared by DXE_RUNTIME variable
3 module and DXE_SMM variable module.
5 Caution: This module requires additional review when modified.
6 This driver will have external input - variable data. They may be input in SMM mode.
7 This external input must be validated carefully to avoid security issue like
8 buffer overflow, integer overflow.
10 VariableServiceGetNextVariableName () and VariableServiceQueryVariableInfo() are external API.
11 They need check input parameter.
13 VariableServiceGetVariable() and VariableServiceSetVariable() are external API
14 to receive datasize and data buffer. The size should be checked carefully.
16 VariableServiceSetVariable() should also check authenticate data to avoid buffer overflow,
17 integer overflow. It should also check attribute to avoid authentication bypass.
19 Copyright (c) 2006 - 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.
32 VARIABLE_MODULE_GLOBAL
*mVariableModuleGlobal
;
35 /// Define a memory cache that improves the search performance for a variable.
37 VARIABLE_STORE_HEADER
*mNvVariableCache
= NULL
;
40 /// The memory entry used for variable statistics data.
42 VARIABLE_INFO_ENTRY
*gVariableInfo
= NULL
;
45 /// The list to store the variables which cannot be set after the EFI_END_OF_DXE_EVENT_GROUP_GUID
46 /// or EVT_GROUP_READY_TO_BOOT event.
48 LIST_ENTRY mLockedVariableList
= INITIALIZE_LIST_HEAD_VARIABLE (mLockedVariableList
);
51 /// The flag to indicate whether the platform has left the DXE phase of execution.
53 BOOLEAN mEndOfDxe
= FALSE
;
56 /// The flag to indicate whether the variable storage locking is enabled.
58 BOOLEAN mEnableLocking
= TRUE
;
61 // It will record the current boot error flag before EndOfDxe.
63 VAR_ERROR_FLAG mCurrentBootVarErrFlag
= VAR_ERROR_FLAG_NO_ERROR
;
65 VARIABLE_ENTRY_PROPERTY mVariableEntryProperty
[] = {
67 &gEdkiiVarErrorFlagGuid
,
70 VAR_CHECK_VARIABLE_PROPERTY_REVISION
,
71 VAR_CHECK_VARIABLE_PROPERTY_READ_ONLY
,
72 VARIABLE_ATTRIBUTE_NV_BS_RT
,
73 sizeof (VAR_ERROR_FLAG
),
74 sizeof (VAR_ERROR_FLAG
)
79 AUTH_VAR_LIB_CONTEXT_IN mContextIn
= {
80 AUTH_VAR_LIB_CONTEXT_IN_STRUCT_VERSION
,
81 sizeof (AUTH_VAR_LIB_CONTEXT_IN
),
83 // MaxAuthVariableSize, TO BE FILLED
86 VariableExLibFindVariable
,
87 VariableExLibFindNextVariable
,
88 VariableExLibUpdateVariable
,
89 VariableExLibGetScratchBuffer
,
90 VariableExLibCheckRemainingSpaceForConsistency
,
91 VariableExLibAtRuntime
,
94 AUTH_VAR_LIB_CONTEXT_OUT mContextOut
;
98 SecureBoot Hook for auth variable update.
100 @param[in] VariableName Name of Variable to be found.
101 @param[in] VendorGuid Variable vendor GUID.
106 IN CHAR16
*VariableName
,
107 IN EFI_GUID
*VendorGuid
111 Routine used to track statistical information about variable usage.
112 The data is stored in the EFI system table so it can be accessed later.
113 VariableInfo.efi can dump out the table. Only Boot Services variable
114 accesses are tracked by this code. The PcdVariableCollectStatistics
115 build flag controls if this feature is enabled.
117 A read that hits in the cache will have Read and Cache true for
118 the transaction. Data is allocated by this routine, but never
121 @param[in] VariableName Name of the Variable to track.
122 @param[in] VendorGuid Guid of the Variable to track.
123 @param[in] Volatile TRUE if volatile FALSE if non-volatile.
124 @param[in] Read TRUE if GetVariable() was called.
125 @param[in] Write TRUE if SetVariable() was called.
126 @param[in] Delete TRUE if deleted via SetVariable().
127 @param[in] Cache TRUE for a cache hit.
132 IN CHAR16
*VariableName
,
133 IN EFI_GUID
*VendorGuid
,
141 VARIABLE_INFO_ENTRY
*Entry
;
143 if (FeaturePcdGet (PcdVariableCollectStatistics
)) {
146 // Don't collect statistics at runtime.
150 if (gVariableInfo
== NULL
) {
152 // On the first call allocate a entry and place a pointer to it in
153 // the EFI System Table.
155 gVariableInfo
= AllocateZeroPool (sizeof (VARIABLE_INFO_ENTRY
));
156 ASSERT (gVariableInfo
!= NULL
);
158 CopyGuid (&gVariableInfo
->VendorGuid
, VendorGuid
);
159 gVariableInfo
->Name
= AllocateZeroPool (StrSize (VariableName
));
160 ASSERT (gVariableInfo
->Name
!= NULL
);
161 StrnCpy (gVariableInfo
->Name
, VariableName
, StrLen (VariableName
));
162 gVariableInfo
->Volatile
= Volatile
;
166 for (Entry
= gVariableInfo
; Entry
!= NULL
; Entry
= Entry
->Next
) {
167 if (CompareGuid (VendorGuid
, &Entry
->VendorGuid
)) {
168 if (StrCmp (VariableName
, Entry
->Name
) == 0) {
176 Entry
->DeleteCount
++;
186 if (Entry
->Next
== NULL
) {
188 // If the entry is not in the table add it.
189 // Next iteration of the loop will fill in the data.
191 Entry
->Next
= AllocateZeroPool (sizeof (VARIABLE_INFO_ENTRY
));
192 ASSERT (Entry
->Next
!= NULL
);
194 CopyGuid (&Entry
->Next
->VendorGuid
, VendorGuid
);
195 Entry
->Next
->Name
= AllocateZeroPool (StrSize (VariableName
));
196 ASSERT (Entry
->Next
->Name
!= NULL
);
197 StrnCpy (Entry
->Next
->Name
, VariableName
, StrLen (VariableName
));
198 Entry
->Next
->Volatile
= Volatile
;
208 This code checks if variable header is valid or not.
210 @param Variable Pointer to the Variable Header.
211 @param VariableStoreEnd Pointer to the Variable Store End.
213 @retval TRUE Variable header is valid.
214 @retval FALSE Variable header is not valid.
218 IsValidVariableHeader (
219 IN VARIABLE_HEADER
*Variable
,
220 IN VARIABLE_HEADER
*VariableStoreEnd
223 if ((Variable
== NULL
) || (Variable
>= VariableStoreEnd
) || (Variable
->StartId
!= VARIABLE_DATA
)) {
225 // Variable is NULL or has reached the end of variable store,
226 // or the StartId is not correct.
237 This function writes data to the FWH at the correct LBA even if the LBAs
240 @param Global Pointer to VARAIBLE_GLOBAL structure.
241 @param Volatile Point out the Variable is Volatile or Non-Volatile.
242 @param SetByIndex TRUE if target pointer is given as index.
243 FALSE if target pointer is absolute.
244 @param Fvb Pointer to the writable FVB protocol.
245 @param DataPtrIndex Pointer to the Data from the end of VARIABLE_STORE_HEADER
247 @param DataSize Size of data to be written.
248 @param Buffer Pointer to the buffer from which data is written.
250 @retval EFI_INVALID_PARAMETER Parameters not valid.
251 @retval EFI_SUCCESS Variable store successfully updated.
255 UpdateVariableStore (
256 IN VARIABLE_GLOBAL
*Global
,
258 IN BOOLEAN SetByIndex
,
259 IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*Fvb
,
260 IN UINTN DataPtrIndex
,
265 EFI_FV_BLOCK_MAP_ENTRY
*PtrBlockMapEntry
;
273 EFI_FIRMWARE_VOLUME_HEADER
*FwVolHeader
;
274 VARIABLE_STORE_HEADER
*VolatileBase
;
275 EFI_PHYSICAL_ADDRESS FvVolHdr
;
276 EFI_PHYSICAL_ADDRESS DataPtr
;
280 DataPtr
= DataPtrIndex
;
283 // Check if the Data is Volatile.
287 return EFI_INVALID_PARAMETER
;
289 Status
= Fvb
->GetPhysicalAddress(Fvb
, &FvVolHdr
);
290 ASSERT_EFI_ERROR (Status
);
292 FwVolHeader
= (EFI_FIRMWARE_VOLUME_HEADER
*) ((UINTN
) FvVolHdr
);
294 // Data Pointer should point to the actual Address where data is to be
298 DataPtr
+= mVariableModuleGlobal
->VariableGlobal
.NonVolatileVariableBase
;
301 if ((DataPtr
+ DataSize
) >= ((EFI_PHYSICAL_ADDRESS
) (UINTN
) ((UINT8
*) FwVolHeader
+ FwVolHeader
->FvLength
))) {
302 return EFI_INVALID_PARAMETER
;
306 // Data Pointer should point to the actual Address where data is to be
309 VolatileBase
= (VARIABLE_STORE_HEADER
*) ((UINTN
) mVariableModuleGlobal
->VariableGlobal
.VolatileVariableBase
);
311 DataPtr
+= mVariableModuleGlobal
->VariableGlobal
.VolatileVariableBase
;
314 if ((DataPtr
+ DataSize
) >= ((UINTN
) ((UINT8
*) VolatileBase
+ VolatileBase
->Size
))) {
315 return EFI_INVALID_PARAMETER
;
319 // If Volatile Variable just do a simple mem copy.
321 CopyMem ((UINT8
*)(UINTN
)DataPtr
, Buffer
, DataSize
);
326 // If we are here we are dealing with Non-Volatile Variables.
328 LinearOffset
= (UINTN
) FwVolHeader
;
329 CurrWritePtr
= (UINTN
) DataPtr
;
330 CurrWriteSize
= DataSize
;
334 if (CurrWritePtr
< LinearOffset
) {
335 return EFI_INVALID_PARAMETER
;
338 for (PtrBlockMapEntry
= FwVolHeader
->BlockMap
; PtrBlockMapEntry
->NumBlocks
!= 0; PtrBlockMapEntry
++) {
339 for (BlockIndex2
= 0; BlockIndex2
< PtrBlockMapEntry
->NumBlocks
; BlockIndex2
++) {
341 // Check to see if the Variable Writes are spanning through multiple
344 if ((CurrWritePtr
>= LinearOffset
) && (CurrWritePtr
< LinearOffset
+ PtrBlockMapEntry
->Length
)) {
345 if ((CurrWritePtr
+ CurrWriteSize
) <= (LinearOffset
+ PtrBlockMapEntry
->Length
)) {
346 Status
= Fvb
->Write (
349 (UINTN
) (CurrWritePtr
- LinearOffset
),
355 Size
= (UINT32
) (LinearOffset
+ PtrBlockMapEntry
->Length
- CurrWritePtr
);
356 Status
= Fvb
->Write (
359 (UINTN
) (CurrWritePtr
- LinearOffset
),
363 if (EFI_ERROR (Status
)) {
367 CurrWritePtr
= LinearOffset
+ PtrBlockMapEntry
->Length
;
368 CurrBuffer
= CurrBuffer
+ Size
;
369 CurrWriteSize
= CurrWriteSize
- Size
;
373 LinearOffset
+= PtrBlockMapEntry
->Length
;
384 This code gets the current status of Variable Store.
386 @param VarStoreHeader Pointer to the Variable Store Header.
388 @retval EfiRaw Variable store status is raw.
389 @retval EfiValid Variable store status is valid.
390 @retval EfiInvalid Variable store status is invalid.
393 VARIABLE_STORE_STATUS
394 GetVariableStoreStatus (
395 IN VARIABLE_STORE_HEADER
*VarStoreHeader
398 if ((CompareGuid (&VarStoreHeader
->Signature
, &gEfiAuthenticatedVariableGuid
) ||
399 CompareGuid (&VarStoreHeader
->Signature
, &gEfiVariableGuid
)) &&
400 VarStoreHeader
->Format
== VARIABLE_STORE_FORMATTED
&&
401 VarStoreHeader
->State
== VARIABLE_STORE_HEALTHY
405 } else if (((UINT32
*)(&VarStoreHeader
->Signature
))[0] == 0xffffffff &&
406 ((UINT32
*)(&VarStoreHeader
->Signature
))[1] == 0xffffffff &&
407 ((UINT32
*)(&VarStoreHeader
->Signature
))[2] == 0xffffffff &&
408 ((UINT32
*)(&VarStoreHeader
->Signature
))[3] == 0xffffffff &&
409 VarStoreHeader
->Size
== 0xffffffff &&
410 VarStoreHeader
->Format
== 0xff &&
411 VarStoreHeader
->State
== 0xff
421 This code gets the size of variable header.
423 @return Size of variable header in bytes in type UINTN.
427 GetVariableHeaderSize (
433 if (mVariableModuleGlobal
->VariableGlobal
.AuthFormat
) {
434 Value
= sizeof (AUTHENTICATED_VARIABLE_HEADER
);
436 Value
= sizeof (VARIABLE_HEADER
);
444 This code gets the size of name of variable.
446 @param Variable Pointer to the Variable Header.
448 @return UINTN Size of variable in bytes.
453 IN VARIABLE_HEADER
*Variable
456 AUTHENTICATED_VARIABLE_HEADER
*AuthVariable
;
458 AuthVariable
= (AUTHENTICATED_VARIABLE_HEADER
*) Variable
;
459 if (mVariableModuleGlobal
->VariableGlobal
.AuthFormat
) {
460 if (AuthVariable
->State
== (UINT8
) (-1) ||
461 AuthVariable
->DataSize
== (UINT32
) (-1) ||
462 AuthVariable
->NameSize
== (UINT32
) (-1) ||
463 AuthVariable
->Attributes
== (UINT32
) (-1)) {
466 return (UINTN
) AuthVariable
->NameSize
;
468 if (Variable
->State
== (UINT8
) (-1) ||
469 Variable
->DataSize
== (UINT32
) (-1) ||
470 Variable
->NameSize
== (UINT32
) (-1) ||
471 Variable
->Attributes
== (UINT32
) (-1)) {
474 return (UINTN
) Variable
->NameSize
;
479 This code sets the size of name of variable.
481 @param[in] Variable Pointer to the Variable Header.
482 @param[in] NameSize Name size to set.
486 SetNameSizeOfVariable (
487 IN VARIABLE_HEADER
*Variable
,
491 AUTHENTICATED_VARIABLE_HEADER
*AuthVariable
;
493 AuthVariable
= (AUTHENTICATED_VARIABLE_HEADER
*) Variable
;
494 if (mVariableModuleGlobal
->VariableGlobal
.AuthFormat
) {
495 AuthVariable
->NameSize
= (UINT32
) NameSize
;
497 Variable
->NameSize
= (UINT32
) NameSize
;
503 This code gets the size of variable data.
505 @param Variable Pointer to the Variable Header.
507 @return Size of variable in bytes.
512 IN VARIABLE_HEADER
*Variable
515 AUTHENTICATED_VARIABLE_HEADER
*AuthVariable
;
517 AuthVariable
= (AUTHENTICATED_VARIABLE_HEADER
*) Variable
;
518 if (mVariableModuleGlobal
->VariableGlobal
.AuthFormat
) {
519 if (AuthVariable
->State
== (UINT8
) (-1) ||
520 AuthVariable
->DataSize
== (UINT32
) (-1) ||
521 AuthVariable
->NameSize
== (UINT32
) (-1) ||
522 AuthVariable
->Attributes
== (UINT32
) (-1)) {
525 return (UINTN
) AuthVariable
->DataSize
;
527 if (Variable
->State
== (UINT8
) (-1) ||
528 Variable
->DataSize
== (UINT32
) (-1) ||
529 Variable
->NameSize
== (UINT32
) (-1) ||
530 Variable
->Attributes
== (UINT32
) (-1)) {
533 return (UINTN
) Variable
->DataSize
;
538 This code sets the size of variable data.
540 @param[in] Variable Pointer to the Variable Header.
541 @param[in] DataSize Data size to set.
545 SetDataSizeOfVariable (
546 IN VARIABLE_HEADER
*Variable
,
550 AUTHENTICATED_VARIABLE_HEADER
*AuthVariable
;
552 AuthVariable
= (AUTHENTICATED_VARIABLE_HEADER
*) Variable
;
553 if (mVariableModuleGlobal
->VariableGlobal
.AuthFormat
) {
554 AuthVariable
->DataSize
= (UINT32
) DataSize
;
556 Variable
->DataSize
= (UINT32
) DataSize
;
562 This code gets the pointer to the variable name.
564 @param Variable Pointer to the Variable Header.
566 @return Pointer to Variable Name which is Unicode encoding.
571 IN VARIABLE_HEADER
*Variable
574 return (CHAR16
*) ((UINTN
) Variable
+ GetVariableHeaderSize ());
578 This code gets the pointer to the variable guid.
580 @param Variable Pointer to the Variable Header.
582 @return A EFI_GUID* pointer to Vendor Guid.
587 IN VARIABLE_HEADER
*Variable
590 AUTHENTICATED_VARIABLE_HEADER
*AuthVariable
;
592 AuthVariable
= (AUTHENTICATED_VARIABLE_HEADER
*) Variable
;
593 if (mVariableModuleGlobal
->VariableGlobal
.AuthFormat
) {
594 return &AuthVariable
->VendorGuid
;
596 return &Variable
->VendorGuid
;
602 This code gets the pointer to the variable data.
604 @param Variable Pointer to the Variable Header.
606 @return Pointer to Variable Data.
611 IN VARIABLE_HEADER
*Variable
617 // Be careful about pad size for alignment.
619 Value
= (UINTN
) GetVariableNamePtr (Variable
);
620 Value
+= NameSizeOfVariable (Variable
);
621 Value
+= GET_PAD_SIZE (NameSizeOfVariable (Variable
));
623 return (UINT8
*) Value
;
627 This code gets the variable data offset related to variable header.
629 @param Variable Pointer to the Variable Header.
631 @return Variable Data offset.
635 GetVariableDataOffset (
636 IN VARIABLE_HEADER
*Variable
642 // Be careful about pad size for alignment
644 Value
= GetVariableHeaderSize ();
645 Value
+= NameSizeOfVariable (Variable
);
646 Value
+= GET_PAD_SIZE (NameSizeOfVariable (Variable
));
653 This code gets the pointer to the next variable header.
655 @param Variable Pointer to the Variable Header.
657 @return Pointer to next variable header.
662 IN VARIABLE_HEADER
*Variable
667 Value
= (UINTN
) GetVariableDataPtr (Variable
);
668 Value
+= DataSizeOfVariable (Variable
);
669 Value
+= GET_PAD_SIZE (DataSizeOfVariable (Variable
));
672 // Be careful about pad size for alignment.
674 return (VARIABLE_HEADER
*) HEADER_ALIGN (Value
);
679 Gets the pointer to the first variable header in given variable store area.
681 @param VarStoreHeader Pointer to the Variable Store Header.
683 @return Pointer to the first variable header.
688 IN VARIABLE_STORE_HEADER
*VarStoreHeader
692 // The end of variable store.
694 return (VARIABLE_HEADER
*) HEADER_ALIGN (VarStoreHeader
+ 1);
699 Gets the pointer to the end of the variable storage area.
701 This function gets pointer to the end of the variable storage
702 area, according to the input variable store header.
704 @param VarStoreHeader Pointer to the Variable Store Header.
706 @return Pointer to the end of the variable storage area.
711 IN VARIABLE_STORE_HEADER
*VarStoreHeader
715 // The end of variable store
717 return (VARIABLE_HEADER
*) HEADER_ALIGN ((UINTN
) VarStoreHeader
+ VarStoreHeader
->Size
);
721 Record variable error flag.
723 @param[in] Flag Variable error flag to record.
724 @param[in] VariableName Name of variable.
725 @param[in] VendorGuid Guid of variable.
726 @param[in] Attributes Attributes of the variable.
727 @param[in] VariableSize Size of the variable.
732 IN VAR_ERROR_FLAG Flag
,
733 IN CHAR16
*VariableName
,
734 IN EFI_GUID
*VendorGuid
,
735 IN UINT32 Attributes
,
736 IN UINTN VariableSize
740 VARIABLE_POINTER_TRACK Variable
;
741 VAR_ERROR_FLAG
*VarErrFlag
;
742 VAR_ERROR_FLAG TempFlag
;
745 DEBUG ((EFI_D_ERROR
, "RecordVarErrorFlag (0x%02x) %s:%g - 0x%08x - 0x%x\n", Flag
, VariableName
, VendorGuid
, Attributes
, VariableSize
));
746 if (Flag
== VAR_ERROR_FLAG_SYSTEM_ERROR
) {
748 DEBUG ((EFI_D_ERROR
, "CommonRuntimeVariableSpace = 0x%x - CommonVariableTotalSize = 0x%x\n", mVariableModuleGlobal
->CommonRuntimeVariableSpace
, mVariableModuleGlobal
->CommonVariableTotalSize
));
750 DEBUG ((EFI_D_ERROR
, "CommonVariableSpace = 0x%x - CommonVariableTotalSize = 0x%x\n", mVariableModuleGlobal
->CommonVariableSpace
, mVariableModuleGlobal
->CommonVariableTotalSize
));
753 DEBUG ((EFI_D_ERROR
, "CommonMaxUserVariableSpace = 0x%x - CommonUserVariableTotalSize = 0x%x\n", mVariableModuleGlobal
->CommonMaxUserVariableSpace
, mVariableModuleGlobal
->CommonUserVariableTotalSize
));
759 // Before EndOfDxe, just record the current boot variable error flag to local variable,
760 // and leave the variable error flag in NV flash as the last boot variable error flag.
761 // After EndOfDxe in InitializeVarErrorFlag (), the variable error flag in NV flash
762 // will be initialized to this local current boot variable error flag.
764 mCurrentBootVarErrFlag
&= Flag
;
769 // Record error flag (it should have be initialized).
771 Status
= FindVariable (
773 &gEdkiiVarErrorFlagGuid
,
775 &mVariableModuleGlobal
->VariableGlobal
,
778 if (!EFI_ERROR (Status
)) {
779 VarErrFlag
= (VAR_ERROR_FLAG
*) GetVariableDataPtr (Variable
.CurrPtr
);
780 TempFlag
= *VarErrFlag
;
782 if (TempFlag
== *VarErrFlag
) {
785 Status
= UpdateVariableStore (
786 &mVariableModuleGlobal
->VariableGlobal
,
789 mVariableModuleGlobal
->FvbInstance
,
790 (UINTN
) VarErrFlag
- (UINTN
) mNvVariableCache
+ (UINTN
) mVariableModuleGlobal
->VariableGlobal
.NonVolatileVariableBase
,
794 if (!EFI_ERROR (Status
)) {
796 // Update the data in NV cache.
804 Initialize variable error flag.
806 Before EndOfDxe, the variable indicates the last boot variable error flag,
807 then it means the last boot variable error flag must be got before EndOfDxe.
808 After EndOfDxe, the variable indicates the current boot variable error flag,
809 then it means the current boot variable error flag must be got after EndOfDxe.
813 InitializeVarErrorFlag (
818 VARIABLE_POINTER_TRACK Variable
;
820 VAR_ERROR_FLAG VarErrFlag
;
826 Flag
= mCurrentBootVarErrFlag
;
827 DEBUG ((EFI_D_INFO
, "Initialize variable error flag (%02x)\n", Flag
));
829 Status
= FindVariable (
831 &gEdkiiVarErrorFlagGuid
,
833 &mVariableModuleGlobal
->VariableGlobal
,
836 if (!EFI_ERROR (Status
)) {
837 VarErrFlag
= *((VAR_ERROR_FLAG
*) GetVariableDataPtr (Variable
.CurrPtr
));
838 if (VarErrFlag
== Flag
) {
845 &gEdkiiVarErrorFlagGuid
,
848 VARIABLE_ATTRIBUTE_NV_BS_RT
,
859 @param[in] Variable Pointer to variable header.
861 @retval TRUE User variable.
862 @retval FALSE System variable.
867 IN VARIABLE_HEADER
*Variable
870 VAR_CHECK_VARIABLE_PROPERTY Property
;
873 // Only after End Of Dxe, the variables belong to system variable are fixed.
874 // If PcdMaxUserNvStorageVariableSize is 0, it means user variable share the same NV storage with system variable,
875 // then no need to check if the variable is user variable or not specially.
877 if (mEndOfDxe
&& (mVariableModuleGlobal
->CommonMaxUserVariableSpace
!= mVariableModuleGlobal
->CommonVariableSpace
)) {
878 if (InternalVarCheckVariablePropertyGet (GetVariableNamePtr (Variable
), GetVendorGuidPtr (Variable
), &Property
) == EFI_NOT_FOUND
) {
886 Calculate common user variable total size.
890 CalculateCommonUserVariableTotalSize (
894 VARIABLE_HEADER
*Variable
;
895 VARIABLE_HEADER
*NextVariable
;
897 VAR_CHECK_VARIABLE_PROPERTY Property
;
900 // Only after End Of Dxe, the variables belong to system variable are fixed.
901 // If PcdMaxUserNvStorageVariableSize is 0, it means user variable share the same NV storage with system variable,
902 // then no need to calculate the common user variable total size specially.
904 if (mEndOfDxe
&& (mVariableModuleGlobal
->CommonMaxUserVariableSpace
!= mVariableModuleGlobal
->CommonVariableSpace
)) {
905 Variable
= GetStartPointer (mNvVariableCache
);
906 while (IsValidVariableHeader (Variable
, GetEndPointer (mNvVariableCache
))) {
907 NextVariable
= GetNextVariablePtr (Variable
);
908 VariableSize
= (UINTN
) NextVariable
- (UINTN
) Variable
;
909 if ((Variable
->Attributes
& EFI_VARIABLE_HARDWARE_ERROR_RECORD
) != EFI_VARIABLE_HARDWARE_ERROR_RECORD
) {
910 if (InternalVarCheckVariablePropertyGet (GetVariableNamePtr (Variable
), GetVendorGuidPtr (Variable
), &Property
) == EFI_NOT_FOUND
) {
912 // No property, it is user variable.
914 mVariableModuleGlobal
->CommonUserVariableTotalSize
+= VariableSize
;
918 Variable
= NextVariable
;
924 Initialize variable quota.
928 InitializeVariableQuota (
932 STATIC BOOLEAN Initialized
;
934 if (!mEndOfDxe
|| Initialized
) {
939 InitializeVarErrorFlag ();
940 CalculateCommonUserVariableTotalSize ();
945 Variable store garbage collection and reclaim operation.
947 @param[in] VariableBase Base address of variable store.
948 @param[out] LastVariableOffset Offset of last variable.
949 @param[in] IsVolatile The variable store is volatile or not;
950 if it is non-volatile, need FTW.
951 @param[in, out] UpdatingPtrTrack Pointer to updating variable pointer track structure.
952 @param[in] NewVariable Pointer to new variable.
953 @param[in] NewVariableSize New variable size.
955 @return EFI_SUCCESS Reclaim operation has finished successfully.
956 @return EFI_OUT_OF_RESOURCES No enough memory resources or variable space.
957 @return Others Unexpect error happened during reclaim operation.
962 IN EFI_PHYSICAL_ADDRESS VariableBase
,
963 OUT UINTN
*LastVariableOffset
,
964 IN BOOLEAN IsVolatile
,
965 IN OUT VARIABLE_POINTER_TRACK
*UpdatingPtrTrack
,
966 IN VARIABLE_HEADER
*NewVariable
,
967 IN UINTN NewVariableSize
970 VARIABLE_HEADER
*Variable
;
971 VARIABLE_HEADER
*AddedVariable
;
972 VARIABLE_HEADER
*NextVariable
;
973 VARIABLE_HEADER
*NextAddedVariable
;
974 VARIABLE_STORE_HEADER
*VariableStoreHeader
;
976 UINTN MaximumBufferSize
;
984 UINTN CommonVariableTotalSize
;
985 UINTN CommonUserVariableTotalSize
;
986 UINTN HwErrVariableTotalSize
;
987 VARIABLE_HEADER
*UpdatingVariable
;
988 VARIABLE_HEADER
*UpdatingInDeletedTransition
;
990 UpdatingVariable
= NULL
;
991 UpdatingInDeletedTransition
= NULL
;
992 if (UpdatingPtrTrack
!= NULL
) {
993 UpdatingVariable
= UpdatingPtrTrack
->CurrPtr
;
994 UpdatingInDeletedTransition
= UpdatingPtrTrack
->InDeletedTransitionPtr
;
997 VariableStoreHeader
= (VARIABLE_STORE_HEADER
*) ((UINTN
) VariableBase
);
999 CommonVariableTotalSize
= 0;
1000 CommonUserVariableTotalSize
= 0;
1001 HwErrVariableTotalSize
= 0;
1005 // Start Pointers for the variable.
1007 Variable
= GetStartPointer (VariableStoreHeader
);
1008 MaximumBufferSize
= sizeof (VARIABLE_STORE_HEADER
);
1010 while (IsValidVariableHeader (Variable
, GetEndPointer (VariableStoreHeader
))) {
1011 NextVariable
= GetNextVariablePtr (Variable
);
1012 if ((Variable
->State
== VAR_ADDED
|| Variable
->State
== (VAR_IN_DELETED_TRANSITION
& VAR_ADDED
)) &&
1013 Variable
!= UpdatingVariable
&&
1014 Variable
!= UpdatingInDeletedTransition
1016 VariableSize
= (UINTN
) NextVariable
- (UINTN
) Variable
;
1017 MaximumBufferSize
+= VariableSize
;
1020 Variable
= NextVariable
;
1023 if (NewVariable
!= NULL
) {
1025 // Add the new variable size.
1027 MaximumBufferSize
+= NewVariableSize
;
1031 // Reserve the 1 Bytes with Oxff to identify the
1032 // end of the variable buffer.
1034 MaximumBufferSize
+= 1;
1035 ValidBuffer
= AllocatePool (MaximumBufferSize
);
1036 if (ValidBuffer
== NULL
) {
1037 return EFI_OUT_OF_RESOURCES
;
1041 // For NV variable reclaim, don't allocate pool here and just use mNvVariableCache
1042 // as the buffer to reduce SMRAM consumption for SMM variable driver.
1044 MaximumBufferSize
= mNvVariableCache
->Size
;
1045 ValidBuffer
= (UINT8
*) mNvVariableCache
;
1048 SetMem (ValidBuffer
, MaximumBufferSize
, 0xff);
1051 // Copy variable store header.
1053 CopyMem (ValidBuffer
, VariableStoreHeader
, sizeof (VARIABLE_STORE_HEADER
));
1054 CurrPtr
= (UINT8
*) GetStartPointer ((VARIABLE_STORE_HEADER
*) ValidBuffer
);
1057 // Reinstall all ADDED variables as long as they are not identical to Updating Variable.
1059 Variable
= GetStartPointer (VariableStoreHeader
);
1060 while (IsValidVariableHeader (Variable
, GetEndPointer (VariableStoreHeader
))) {
1061 NextVariable
= GetNextVariablePtr (Variable
);
1062 if (Variable
!= UpdatingVariable
&& Variable
->State
== VAR_ADDED
) {
1063 VariableSize
= (UINTN
) NextVariable
- (UINTN
) Variable
;
1064 CopyMem (CurrPtr
, (UINT8
*) Variable
, VariableSize
);
1065 CurrPtr
+= VariableSize
;
1066 if ((!IsVolatile
) && ((Variable
->Attributes
& EFI_VARIABLE_HARDWARE_ERROR_RECORD
) == EFI_VARIABLE_HARDWARE_ERROR_RECORD
)) {
1067 HwErrVariableTotalSize
+= VariableSize
;
1068 } else if ((!IsVolatile
) && ((Variable
->Attributes
& EFI_VARIABLE_HARDWARE_ERROR_RECORD
) != EFI_VARIABLE_HARDWARE_ERROR_RECORD
)) {
1069 CommonVariableTotalSize
+= VariableSize
;
1070 if (IsUserVariable (Variable
)) {
1071 CommonUserVariableTotalSize
+= VariableSize
;
1075 Variable
= NextVariable
;
1079 // Reinstall all in delete transition variables.
1081 Variable
= GetStartPointer (VariableStoreHeader
);
1082 while (IsValidVariableHeader (Variable
, GetEndPointer (VariableStoreHeader
))) {
1083 NextVariable
= GetNextVariablePtr (Variable
);
1084 if (Variable
!= UpdatingVariable
&& Variable
!= UpdatingInDeletedTransition
&& Variable
->State
== (VAR_IN_DELETED_TRANSITION
& VAR_ADDED
)) {
1087 // Buffer has cached all ADDED variable.
1088 // Per IN_DELETED variable, we have to guarantee that
1089 // no ADDED one in previous buffer.
1093 AddedVariable
= GetStartPointer ((VARIABLE_STORE_HEADER
*) ValidBuffer
);
1094 while (IsValidVariableHeader (AddedVariable
, GetEndPointer ((VARIABLE_STORE_HEADER
*) ValidBuffer
))) {
1095 NextAddedVariable
= GetNextVariablePtr (AddedVariable
);
1096 NameSize
= NameSizeOfVariable (AddedVariable
);
1097 if (CompareGuid (GetVendorGuidPtr (AddedVariable
), GetVendorGuidPtr (Variable
)) &&
1098 NameSize
== NameSizeOfVariable (Variable
)
1100 Point0
= (VOID
*) GetVariableNamePtr (AddedVariable
);
1101 Point1
= (VOID
*) GetVariableNamePtr (Variable
);
1102 if (CompareMem (Point0
, Point1
, NameSize
) == 0) {
1107 AddedVariable
= NextAddedVariable
;
1111 // Promote VAR_IN_DELETED_TRANSITION to VAR_ADDED.
1113 VariableSize
= (UINTN
) NextVariable
- (UINTN
) Variable
;
1114 CopyMem (CurrPtr
, (UINT8
*) Variable
, VariableSize
);
1115 ((VARIABLE_HEADER
*) CurrPtr
)->State
= VAR_ADDED
;
1116 CurrPtr
+= VariableSize
;
1117 if ((!IsVolatile
) && ((Variable
->Attributes
& EFI_VARIABLE_HARDWARE_ERROR_RECORD
) == EFI_VARIABLE_HARDWARE_ERROR_RECORD
)) {
1118 HwErrVariableTotalSize
+= VariableSize
;
1119 } else if ((!IsVolatile
) && ((Variable
->Attributes
& EFI_VARIABLE_HARDWARE_ERROR_RECORD
) != EFI_VARIABLE_HARDWARE_ERROR_RECORD
)) {
1120 CommonVariableTotalSize
+= VariableSize
;
1121 if (IsUserVariable (Variable
)) {
1122 CommonUserVariableTotalSize
+= VariableSize
;
1128 Variable
= NextVariable
;
1132 // Install the new variable if it is not NULL.
1134 if (NewVariable
!= NULL
) {
1135 if ((UINTN
) (CurrPtr
- ValidBuffer
) + NewVariableSize
> VariableStoreHeader
->Size
) {
1137 // No enough space to store the new variable.
1139 Status
= EFI_OUT_OF_RESOURCES
;
1143 if ((NewVariable
->Attributes
& EFI_VARIABLE_HARDWARE_ERROR_RECORD
) == EFI_VARIABLE_HARDWARE_ERROR_RECORD
) {
1144 HwErrVariableTotalSize
+= NewVariableSize
;
1145 } else if ((NewVariable
->Attributes
& EFI_VARIABLE_HARDWARE_ERROR_RECORD
) != EFI_VARIABLE_HARDWARE_ERROR_RECORD
) {
1146 CommonVariableTotalSize
+= NewVariableSize
;
1147 if (IsUserVariable (NewVariable
)) {
1148 CommonUserVariableTotalSize
+= NewVariableSize
;
1151 if ((HwErrVariableTotalSize
> PcdGet32 (PcdHwErrStorageSize
)) ||
1152 (CommonVariableTotalSize
> mVariableModuleGlobal
->CommonVariableSpace
) ||
1153 (CommonUserVariableTotalSize
> mVariableModuleGlobal
->CommonMaxUserVariableSpace
)) {
1155 // No enough space to store the new variable by NV or NV+HR attribute.
1157 Status
= EFI_OUT_OF_RESOURCES
;
1162 CopyMem (CurrPtr
, (UINT8
*) NewVariable
, NewVariableSize
);
1163 ((VARIABLE_HEADER
*) CurrPtr
)->State
= VAR_ADDED
;
1164 if (UpdatingVariable
!= NULL
) {
1165 UpdatingPtrTrack
->CurrPtr
= (VARIABLE_HEADER
*)((UINTN
)UpdatingPtrTrack
->StartPtr
+ ((UINTN
)CurrPtr
- (UINTN
)GetStartPointer ((VARIABLE_STORE_HEADER
*) ValidBuffer
)));
1166 UpdatingPtrTrack
->InDeletedTransitionPtr
= NULL
;
1168 CurrPtr
+= NewVariableSize
;
1173 // If volatile variable store, just copy valid buffer.
1175 SetMem ((UINT8
*) (UINTN
) VariableBase
, VariableStoreHeader
->Size
, 0xff);
1176 CopyMem ((UINT8
*) (UINTN
) VariableBase
, ValidBuffer
, (UINTN
) (CurrPtr
- ValidBuffer
));
1177 *LastVariableOffset
= (UINTN
) (CurrPtr
- ValidBuffer
);
1178 Status
= EFI_SUCCESS
;
1181 // If non-volatile variable store, perform FTW here.
1183 Status
= FtwVariableSpace (
1185 (VARIABLE_STORE_HEADER
*) ValidBuffer
1187 if (!EFI_ERROR (Status
)) {
1188 *LastVariableOffset
= (UINTN
) (CurrPtr
- ValidBuffer
);
1189 mVariableModuleGlobal
->HwErrVariableTotalSize
= HwErrVariableTotalSize
;
1190 mVariableModuleGlobal
->CommonVariableTotalSize
= CommonVariableTotalSize
;
1191 mVariableModuleGlobal
->CommonUserVariableTotalSize
= CommonUserVariableTotalSize
;
1193 Variable
= GetStartPointer ((VARIABLE_STORE_HEADER
*)(UINTN
)VariableBase
);
1194 while (IsValidVariableHeader (Variable
, GetEndPointer ((VARIABLE_STORE_HEADER
*)(UINTN
)VariableBase
))) {
1195 NextVariable
= GetNextVariablePtr (Variable
);
1196 VariableSize
= (UINTN
) NextVariable
- (UINTN
) Variable
;
1197 if ((Variable
->Attributes
& EFI_VARIABLE_HARDWARE_ERROR_RECORD
) == EFI_VARIABLE_HARDWARE_ERROR_RECORD
) {
1198 mVariableModuleGlobal
->HwErrVariableTotalSize
+= VariableSize
;
1199 } else if ((Variable
->Attributes
& EFI_VARIABLE_HARDWARE_ERROR_RECORD
) != EFI_VARIABLE_HARDWARE_ERROR_RECORD
) {
1200 mVariableModuleGlobal
->CommonVariableTotalSize
+= VariableSize
;
1201 if (IsUserVariable (Variable
)) {
1202 mVariableModuleGlobal
->CommonUserVariableTotalSize
+= VariableSize
;
1206 Variable
= NextVariable
;
1208 *LastVariableOffset
= (UINTN
) Variable
- (UINTN
) VariableBase
;
1214 FreePool (ValidBuffer
);
1217 // For NV variable reclaim, we use mNvVariableCache as the buffer, so copy the data back.
1219 CopyMem (mNvVariableCache
, (UINT8
*)(UINTN
)VariableBase
, VariableStoreHeader
->Size
);
1226 Find the variable in the specified variable store.
1228 @param[in] VariableName Name of the variable to be found
1229 @param[in] VendorGuid Vendor GUID to be found.
1230 @param[in] IgnoreRtCheck Ignore EFI_VARIABLE_RUNTIME_ACCESS attribute
1231 check at runtime when searching variable.
1232 @param[in, out] PtrTrack Variable Track Pointer structure that contains Variable Information.
1234 @retval EFI_SUCCESS Variable found successfully
1235 @retval EFI_NOT_FOUND Variable not found
1239 IN CHAR16
*VariableName
,
1240 IN EFI_GUID
*VendorGuid
,
1241 IN BOOLEAN IgnoreRtCheck
,
1242 IN OUT VARIABLE_POINTER_TRACK
*PtrTrack
1245 VARIABLE_HEADER
*InDeletedVariable
;
1248 PtrTrack
->InDeletedTransitionPtr
= NULL
;
1251 // Find the variable by walk through HOB, volatile and non-volatile variable store.
1253 InDeletedVariable
= NULL
;
1255 for ( PtrTrack
->CurrPtr
= PtrTrack
->StartPtr
1256 ; IsValidVariableHeader (PtrTrack
->CurrPtr
, PtrTrack
->EndPtr
)
1257 ; PtrTrack
->CurrPtr
= GetNextVariablePtr (PtrTrack
->CurrPtr
)
1259 if (PtrTrack
->CurrPtr
->State
== VAR_ADDED
||
1260 PtrTrack
->CurrPtr
->State
== (VAR_IN_DELETED_TRANSITION
& VAR_ADDED
)
1262 if (IgnoreRtCheck
|| !AtRuntime () || ((PtrTrack
->CurrPtr
->Attributes
& EFI_VARIABLE_RUNTIME_ACCESS
) != 0)) {
1263 if (VariableName
[0] == 0) {
1264 if (PtrTrack
->CurrPtr
->State
== (VAR_IN_DELETED_TRANSITION
& VAR_ADDED
)) {
1265 InDeletedVariable
= PtrTrack
->CurrPtr
;
1267 PtrTrack
->InDeletedTransitionPtr
= InDeletedVariable
;
1271 if (CompareGuid (VendorGuid
, GetVendorGuidPtr (PtrTrack
->CurrPtr
))) {
1272 Point
= (VOID
*) GetVariableNamePtr (PtrTrack
->CurrPtr
);
1274 ASSERT (NameSizeOfVariable (PtrTrack
->CurrPtr
) != 0);
1275 if (CompareMem (VariableName
, Point
, NameSizeOfVariable (PtrTrack
->CurrPtr
)) == 0) {
1276 if (PtrTrack
->CurrPtr
->State
== (VAR_IN_DELETED_TRANSITION
& VAR_ADDED
)) {
1277 InDeletedVariable
= PtrTrack
->CurrPtr
;
1279 PtrTrack
->InDeletedTransitionPtr
= InDeletedVariable
;
1289 PtrTrack
->CurrPtr
= InDeletedVariable
;
1290 return (PtrTrack
->CurrPtr
== NULL
) ? EFI_NOT_FOUND
: EFI_SUCCESS
;
1295 Finds variable in storage blocks of volatile and non-volatile storage areas.
1297 This code finds variable in storage blocks of volatile and non-volatile storage areas.
1298 If VariableName is an empty string, then we just return the first
1299 qualified variable without comparing VariableName and VendorGuid.
1300 If IgnoreRtCheck is TRUE, then we ignore the EFI_VARIABLE_RUNTIME_ACCESS attribute check
1301 at runtime when searching existing variable, only VariableName and VendorGuid are compared.
1302 Otherwise, variables without EFI_VARIABLE_RUNTIME_ACCESS are not visible at runtime.
1304 @param[in] VariableName Name of the variable to be found.
1305 @param[in] VendorGuid Vendor GUID to be found.
1306 @param[out] PtrTrack VARIABLE_POINTER_TRACK structure for output,
1307 including the range searched and the target position.
1308 @param[in] Global Pointer to VARIABLE_GLOBAL structure, including
1309 base of volatile variable storage area, base of
1310 NV variable storage area, and a lock.
1311 @param[in] IgnoreRtCheck Ignore EFI_VARIABLE_RUNTIME_ACCESS attribute
1312 check at runtime when searching variable.
1314 @retval EFI_INVALID_PARAMETER If VariableName is not an empty string, while
1316 @retval EFI_SUCCESS Variable successfully found.
1317 @retval EFI_NOT_FOUND Variable not found
1322 IN CHAR16
*VariableName
,
1323 IN EFI_GUID
*VendorGuid
,
1324 OUT VARIABLE_POINTER_TRACK
*PtrTrack
,
1325 IN VARIABLE_GLOBAL
*Global
,
1326 IN BOOLEAN IgnoreRtCheck
1330 VARIABLE_STORE_HEADER
*VariableStoreHeader
[VariableStoreTypeMax
];
1331 VARIABLE_STORE_TYPE Type
;
1333 if (VariableName
[0] != 0 && VendorGuid
== NULL
) {
1334 return EFI_INVALID_PARAMETER
;
1338 // 0: Volatile, 1: HOB, 2: Non-Volatile.
1339 // The index and attributes mapping must be kept in this order as RuntimeServiceGetNextVariableName
1340 // make use of this mapping to implement search algorithm.
1342 VariableStoreHeader
[VariableStoreTypeVolatile
] = (VARIABLE_STORE_HEADER
*) (UINTN
) Global
->VolatileVariableBase
;
1343 VariableStoreHeader
[VariableStoreTypeHob
] = (VARIABLE_STORE_HEADER
*) (UINTN
) Global
->HobVariableBase
;
1344 VariableStoreHeader
[VariableStoreTypeNv
] = mNvVariableCache
;
1347 // Find the variable by walk through HOB, volatile and non-volatile variable store.
1349 for (Type
= (VARIABLE_STORE_TYPE
) 0; Type
< VariableStoreTypeMax
; Type
++) {
1350 if (VariableStoreHeader
[Type
] == NULL
) {
1354 PtrTrack
->StartPtr
= GetStartPointer (VariableStoreHeader
[Type
]);
1355 PtrTrack
->EndPtr
= GetEndPointer (VariableStoreHeader
[Type
]);
1356 PtrTrack
->Volatile
= (BOOLEAN
) (Type
== VariableStoreTypeVolatile
);
1358 Status
= FindVariableEx (VariableName
, VendorGuid
, IgnoreRtCheck
, PtrTrack
);
1359 if (!EFI_ERROR (Status
)) {
1363 return EFI_NOT_FOUND
;
1367 Get index from supported language codes according to language string.
1369 This code is used to get corresponding index in supported language codes. It can handle
1370 RFC4646 and ISO639 language tags.
1371 In ISO639 language tags, take 3-characters as a delimitation to find matched string and calculate the index.
1372 In RFC4646 language tags, take semicolon as a delimitation to find matched string and calculate the index.
1375 SupportedLang = "engfraengfra"
1377 Iso639Language = TRUE
1378 The return value is "0".
1380 SupportedLang = "en;fr;en-US;fr-FR"
1382 Iso639Language = FALSE
1383 The return value is "3".
1385 @param SupportedLang Platform supported language codes.
1386 @param Lang Configured language.
1387 @param Iso639Language A bool value to signify if the handler is operated on ISO639 or RFC4646.
1389 @retval The index of language in the language codes.
1393 GetIndexFromSupportedLangCodes(
1394 IN CHAR8
*SupportedLang
,
1396 IN BOOLEAN Iso639Language
1400 UINTN CompareLength
;
1401 UINTN LanguageLength
;
1403 if (Iso639Language
) {
1404 CompareLength
= ISO_639_2_ENTRY_SIZE
;
1405 for (Index
= 0; Index
< AsciiStrLen (SupportedLang
); Index
+= CompareLength
) {
1406 if (AsciiStrnCmp (Lang
, SupportedLang
+ Index
, CompareLength
) == 0) {
1408 // Successfully find the index of Lang string in SupportedLang string.
1410 Index
= Index
/ CompareLength
;
1418 // Compare RFC4646 language code
1421 for (LanguageLength
= 0; Lang
[LanguageLength
] != '\0'; LanguageLength
++);
1423 for (Index
= 0; *SupportedLang
!= '\0'; Index
++, SupportedLang
+= CompareLength
) {
1425 // Skip ';' characters in SupportedLang
1427 for (; *SupportedLang
!= '\0' && *SupportedLang
== ';'; SupportedLang
++);
1429 // Determine the length of the next language code in SupportedLang
1431 for (CompareLength
= 0; SupportedLang
[CompareLength
] != '\0' && SupportedLang
[CompareLength
] != ';'; CompareLength
++);
1433 if ((CompareLength
== LanguageLength
) &&
1434 (AsciiStrnCmp (Lang
, SupportedLang
, CompareLength
) == 0)) {
1436 // Successfully find the index of Lang string in SupportedLang string.
1447 Get language string from supported language codes according to index.
1449 This code is used to get corresponding language strings in supported language codes. It can handle
1450 RFC4646 and ISO639 language tags.
1451 In ISO639 language tags, take 3-characters as a delimitation. Find language string according to the index.
1452 In RFC4646 language tags, take semicolon as a delimitation. Find language string according to the index.
1455 SupportedLang = "engfraengfra"
1457 Iso639Language = TRUE
1458 The return value is "fra".
1460 SupportedLang = "en;fr;en-US;fr-FR"
1462 Iso639Language = FALSE
1463 The return value is "fr".
1465 @param SupportedLang Platform supported language codes.
1466 @param Index The index in supported language codes.
1467 @param Iso639Language A bool value to signify if the handler is operated on ISO639 or RFC4646.
1469 @retval The language string in the language codes.
1473 GetLangFromSupportedLangCodes (
1474 IN CHAR8
*SupportedLang
,
1476 IN BOOLEAN Iso639Language
1480 UINTN CompareLength
;
1484 Supported
= SupportedLang
;
1485 if (Iso639Language
) {
1487 // According to the index of Lang string in SupportedLang string to get the language.
1488 // This code will be invoked in RUNTIME, therefore there is not a memory allocate/free operation.
1489 // In driver entry, it pre-allocates a runtime attribute memory to accommodate this string.
1491 CompareLength
= ISO_639_2_ENTRY_SIZE
;
1492 mVariableModuleGlobal
->Lang
[CompareLength
] = '\0';
1493 return CopyMem (mVariableModuleGlobal
->Lang
, SupportedLang
+ Index
* CompareLength
, CompareLength
);
1498 // Take semicolon as delimitation, sequentially traverse supported language codes.
1500 for (CompareLength
= 0; *Supported
!= ';' && *Supported
!= '\0'; CompareLength
++) {
1503 if ((*Supported
== '\0') && (SubIndex
!= Index
)) {
1505 // Have completed the traverse, but not find corrsponding string.
1506 // This case is not allowed to happen.
1511 if (SubIndex
== Index
) {
1513 // According to the index of Lang string in SupportedLang string to get the language.
1514 // As this code will be invoked in RUNTIME, therefore there is not memory allocate/free operation.
1515 // In driver entry, it pre-allocates a runtime attribute memory to accommodate this string.
1517 mVariableModuleGlobal
->PlatformLang
[CompareLength
] = '\0';
1518 return CopyMem (mVariableModuleGlobal
->PlatformLang
, Supported
- CompareLength
, CompareLength
);
1523 // Skip ';' characters in Supported
1525 for (; *Supported
!= '\0' && *Supported
== ';'; Supported
++);
1531 Returns a pointer to an allocated buffer that contains the best matching language
1532 from a set of supported languages.
1534 This function supports both ISO 639-2 and RFC 4646 language codes, but language
1535 code types may not be mixed in a single call to this function. This function
1536 supports a variable argument list that allows the caller to pass in a prioritized
1537 list of language codes to test against all the language codes in SupportedLanguages.
1539 If SupportedLanguages is NULL, then ASSERT().
1541 @param[in] SupportedLanguages A pointer to a Null-terminated ASCII string that
1542 contains a set of language codes in the format
1543 specified by Iso639Language.
1544 @param[in] Iso639Language If TRUE, then all language codes are assumed to be
1545 in ISO 639-2 format. If FALSE, then all language
1546 codes are assumed to be in RFC 4646 language format
1547 @param[in] ... A variable argument list that contains pointers to
1548 Null-terminated ASCII strings that contain one or more
1549 language codes in the format specified by Iso639Language.
1550 The first language code from each of these language
1551 code lists is used to determine if it is an exact or
1552 close match to any of the language codes in
1553 SupportedLanguages. Close matches only apply to RFC 4646
1554 language codes, and the matching algorithm from RFC 4647
1555 is used to determine if a close match is present. If
1556 an exact or close match is found, then the matching
1557 language code from SupportedLanguages is returned. If
1558 no matches are found, then the next variable argument
1559 parameter is evaluated. The variable argument list
1560 is terminated by a NULL.
1562 @retval NULL The best matching language could not be found in SupportedLanguages.
1563 @retval NULL There are not enough resources available to return the best matching
1565 @retval Other A pointer to a Null-terminated ASCII string that is the best matching
1566 language in SupportedLanguages.
1571 VariableGetBestLanguage (
1572 IN CONST CHAR8
*SupportedLanguages
,
1573 IN BOOLEAN Iso639Language
,
1579 UINTN CompareLength
;
1580 UINTN LanguageLength
;
1581 CONST CHAR8
*Supported
;
1584 if (SupportedLanguages
== NULL
) {
1588 VA_START (Args
, Iso639Language
);
1589 while ((Language
= VA_ARG (Args
, CHAR8
*)) != NULL
) {
1591 // Default to ISO 639-2 mode
1594 LanguageLength
= MIN (3, AsciiStrLen (Language
));
1597 // If in RFC 4646 mode, then determine the length of the first RFC 4646 language code in Language
1599 if (!Iso639Language
) {
1600 for (LanguageLength
= 0; Language
[LanguageLength
] != 0 && Language
[LanguageLength
] != ';'; LanguageLength
++);
1604 // Trim back the length of Language used until it is empty
1606 while (LanguageLength
> 0) {
1608 // Loop through all language codes in SupportedLanguages
1610 for (Supported
= SupportedLanguages
; *Supported
!= '\0'; Supported
+= CompareLength
) {
1612 // In RFC 4646 mode, then Loop through all language codes in SupportedLanguages
1614 if (!Iso639Language
) {
1616 // Skip ';' characters in Supported
1618 for (; *Supported
!= '\0' && *Supported
== ';'; Supported
++);
1620 // Determine the length of the next language code in Supported
1622 for (CompareLength
= 0; Supported
[CompareLength
] != 0 && Supported
[CompareLength
] != ';'; CompareLength
++);
1624 // If Language is longer than the Supported, then skip to the next language
1626 if (LanguageLength
> CompareLength
) {
1631 // See if the first LanguageLength characters in Supported match Language
1633 if (AsciiStrnCmp (Supported
, Language
, LanguageLength
) == 0) {
1636 Buffer
= Iso639Language
? mVariableModuleGlobal
->Lang
: mVariableModuleGlobal
->PlatformLang
;
1637 Buffer
[CompareLength
] = '\0';
1638 return CopyMem (Buffer
, Supported
, CompareLength
);
1642 if (Iso639Language
) {
1644 // If ISO 639 mode, then each language can only be tested once
1649 // If RFC 4646 mode, then trim Language from the right to the next '-' character
1651 for (LanguageLength
--; LanguageLength
> 0 && Language
[LanguageLength
] != '-'; LanguageLength
--);
1658 // No matches were found
1664 This function is to check if the remaining variable space is enough to set
1665 all Variables from argument list successfully. The purpose of the check
1666 is to keep the consistency of the Variables to be in variable storage.
1668 Note: Variables are assumed to be in same storage.
1669 The set sequence of Variables will be same with the sequence of VariableEntry from argument list,
1670 so follow the argument sequence to check the Variables.
1672 @param[in] Attributes Variable attributes for Variable entries.
1673 @param[in] Marker VA_LIST style variable argument list.
1674 The variable argument list with type VARIABLE_ENTRY_CONSISTENCY *.
1675 A NULL terminates the list. The VariableSize of
1676 VARIABLE_ENTRY_CONSISTENCY is the variable data size as input.
1677 It will be changed to variable total size as output.
1679 @retval TRUE Have enough variable space to set the Variables successfully.
1680 @retval FALSE No enough variable space to set the Variables successfully.
1685 CheckRemainingSpaceForConsistencyInternal (
1686 IN UINT32 Attributes
,
1692 VARIABLE_ENTRY_CONSISTENCY
*VariableEntry
;
1693 UINT64 MaximumVariableStorageSize
;
1694 UINT64 RemainingVariableStorageSize
;
1695 UINT64 MaximumVariableSize
;
1696 UINTN TotalNeededSize
;
1697 UINTN OriginalVarSize
;
1698 VARIABLE_STORE_HEADER
*VariableStoreHeader
;
1699 VARIABLE_POINTER_TRACK VariablePtrTrack
;
1700 VARIABLE_HEADER
*NextVariable
;
1705 // Non-Volatile related.
1707 VariableStoreHeader
= mNvVariableCache
;
1709 Status
= VariableServiceQueryVariableInfoInternal (
1711 &MaximumVariableStorageSize
,
1712 &RemainingVariableStorageSize
,
1713 &MaximumVariableSize
1715 ASSERT_EFI_ERROR (Status
);
1717 TotalNeededSize
= 0;
1719 VariableEntry
= VA_ARG (Args
, VARIABLE_ENTRY_CONSISTENCY
*);
1720 while (VariableEntry
!= NULL
) {
1722 // Calculate variable total size.
1724 VarNameSize
= StrSize (VariableEntry
->Name
);
1725 VarNameSize
+= GET_PAD_SIZE (VarNameSize
);
1726 VarDataSize
= VariableEntry
->VariableSize
;
1727 VarDataSize
+= GET_PAD_SIZE (VarDataSize
);
1728 VariableEntry
->VariableSize
= HEADER_ALIGN (GetVariableHeaderSize () + VarNameSize
+ VarDataSize
);
1730 TotalNeededSize
+= VariableEntry
->VariableSize
;
1731 VariableEntry
= VA_ARG (Args
, VARIABLE_ENTRY_CONSISTENCY
*);
1734 if (RemainingVariableStorageSize
>= TotalNeededSize
) {
1736 // Already have enough space.
1739 } else if (AtRuntime ()) {
1741 // At runtime, no reclaim.
1742 // The original variable space of Variables can't be reused.
1748 VariableEntry
= VA_ARG (Args
, VARIABLE_ENTRY_CONSISTENCY
*);
1749 while (VariableEntry
!= NULL
) {
1751 // Check if Variable[Index] has been present and get its size.
1753 OriginalVarSize
= 0;
1754 VariablePtrTrack
.StartPtr
= GetStartPointer (VariableStoreHeader
);
1755 VariablePtrTrack
.EndPtr
= GetEndPointer (VariableStoreHeader
);
1756 Status
= FindVariableEx (
1757 VariableEntry
->Name
,
1758 VariableEntry
->Guid
,
1762 if (!EFI_ERROR (Status
)) {
1764 // Get size of Variable[Index].
1766 NextVariable
= GetNextVariablePtr (VariablePtrTrack
.CurrPtr
);
1767 OriginalVarSize
= (UINTN
) NextVariable
- (UINTN
) VariablePtrTrack
.CurrPtr
;
1769 // Add the original size of Variable[Index] to remaining variable storage size.
1771 RemainingVariableStorageSize
+= OriginalVarSize
;
1773 if (VariableEntry
->VariableSize
> RemainingVariableStorageSize
) {
1775 // No enough space for Variable[Index].
1780 // Sub the (new) size of Variable[Index] from remaining variable storage size.
1782 RemainingVariableStorageSize
-= VariableEntry
->VariableSize
;
1783 VariableEntry
= VA_ARG (Args
, VARIABLE_ENTRY_CONSISTENCY
*);
1790 This function is to check if the remaining variable space is enough to set
1791 all Variables from argument list successfully. The purpose of the check
1792 is to keep the consistency of the Variables to be in variable storage.
1794 Note: Variables are assumed to be in same storage.
1795 The set sequence of Variables will be same with the sequence of VariableEntry from argument list,
1796 so follow the argument sequence to check the Variables.
1798 @param[in] Attributes Variable attributes for Variable entries.
1799 @param ... The variable argument list with type VARIABLE_ENTRY_CONSISTENCY *.
1800 A NULL terminates the list. The VariableSize of
1801 VARIABLE_ENTRY_CONSISTENCY is the variable data size as input.
1802 It will be changed to variable total size as output.
1804 @retval TRUE Have enough variable space to set the Variables successfully.
1805 @retval FALSE No enough variable space to set the Variables successfully.
1810 CheckRemainingSpaceForConsistency (
1811 IN UINT32 Attributes
,
1818 VA_START (Marker
, Attributes
);
1820 Return
= CheckRemainingSpaceForConsistencyInternal (Attributes
, Marker
);
1828 Hook the operations in PlatformLangCodes, LangCodes, PlatformLang and Lang.
1830 When setting Lang/LangCodes, simultaneously update PlatformLang/PlatformLangCodes.
1832 According to UEFI spec, PlatformLangCodes/LangCodes are only set once in firmware initialization,
1833 and are read-only. Therefore, in variable driver, only store the original value for other use.
1835 @param[in] VariableName Name of variable.
1837 @param[in] Data Variable data.
1839 @param[in] DataSize Size of data. 0 means delete.
1841 @retval EFI_SUCCESS The update operation is successful or ignored.
1842 @retval EFI_WRITE_PROTECTED Update PlatformLangCodes/LangCodes at runtime.
1843 @retval EFI_OUT_OF_RESOURCES No enough variable space to do the update operation.
1844 @retval Others Other errors happened during the update operation.
1848 AutoUpdateLangVariable (
1849 IN CHAR16
*VariableName
,
1855 CHAR8
*BestPlatformLang
;
1859 VARIABLE_POINTER_TRACK Variable
;
1860 BOOLEAN SetLanguageCodes
;
1861 VARIABLE_ENTRY_CONSISTENCY VariableEntry
[2];
1864 // Don't do updates for delete operation
1866 if (DataSize
== 0) {
1870 SetLanguageCodes
= FALSE
;
1872 if (StrCmp (VariableName
, EFI_PLATFORM_LANG_CODES_VARIABLE_NAME
) == 0) {
1874 // PlatformLangCodes is a volatile variable, so it can not be updated at runtime.
1877 return EFI_WRITE_PROTECTED
;
1880 SetLanguageCodes
= TRUE
;
1883 // According to UEFI spec, PlatformLangCodes is only set once in firmware initialization, and is read-only
1884 // Therefore, in variable driver, only store the original value for other use.
1886 if (mVariableModuleGlobal
->PlatformLangCodes
!= NULL
) {
1887 FreePool (mVariableModuleGlobal
->PlatformLangCodes
);
1889 mVariableModuleGlobal
->PlatformLangCodes
= AllocateRuntimeCopyPool (DataSize
, Data
);
1890 ASSERT (mVariableModuleGlobal
->PlatformLangCodes
!= NULL
);
1893 // PlatformLang holds a single language from PlatformLangCodes,
1894 // so the size of PlatformLangCodes is enough for the PlatformLang.
1896 if (mVariableModuleGlobal
->PlatformLang
!= NULL
) {
1897 FreePool (mVariableModuleGlobal
->PlatformLang
);
1899 mVariableModuleGlobal
->PlatformLang
= AllocateRuntimePool (DataSize
);
1900 ASSERT (mVariableModuleGlobal
->PlatformLang
!= NULL
);
1902 } else if (StrCmp (VariableName
, EFI_LANG_CODES_VARIABLE_NAME
) == 0) {
1904 // LangCodes is a volatile variable, so it can not be updated at runtime.
1907 return EFI_WRITE_PROTECTED
;
1910 SetLanguageCodes
= TRUE
;
1913 // According to UEFI spec, LangCodes is only set once in firmware initialization, and is read-only
1914 // Therefore, in variable driver, only store the original value for other use.
1916 if (mVariableModuleGlobal
->LangCodes
!= NULL
) {
1917 FreePool (mVariableModuleGlobal
->LangCodes
);
1919 mVariableModuleGlobal
->LangCodes
= AllocateRuntimeCopyPool (DataSize
, Data
);
1920 ASSERT (mVariableModuleGlobal
->LangCodes
!= NULL
);
1923 if (SetLanguageCodes
1924 && (mVariableModuleGlobal
->PlatformLangCodes
!= NULL
)
1925 && (mVariableModuleGlobal
->LangCodes
!= NULL
)) {
1927 // Update Lang if PlatformLang is already set
1928 // Update PlatformLang if Lang is already set
1930 Status
= FindVariable (EFI_PLATFORM_LANG_VARIABLE_NAME
, &gEfiGlobalVariableGuid
, &Variable
, &mVariableModuleGlobal
->VariableGlobal
, FALSE
);
1931 if (!EFI_ERROR (Status
)) {
1935 VariableName
= EFI_PLATFORM_LANG_VARIABLE_NAME
;
1936 Data
= GetVariableDataPtr (Variable
.CurrPtr
);
1937 DataSize
= DataSizeOfVariable (Variable
.CurrPtr
);
1939 Status
= FindVariable (EFI_LANG_VARIABLE_NAME
, &gEfiGlobalVariableGuid
, &Variable
, &mVariableModuleGlobal
->VariableGlobal
, FALSE
);
1940 if (!EFI_ERROR (Status
)) {
1942 // Update PlatformLang
1944 VariableName
= EFI_LANG_VARIABLE_NAME
;
1945 Data
= GetVariableDataPtr (Variable
.CurrPtr
);
1946 DataSize
= DataSizeOfVariable (Variable
.CurrPtr
);
1949 // Neither PlatformLang nor Lang is set, directly return
1956 Status
= EFI_SUCCESS
;
1959 // According to UEFI spec, "Lang" and "PlatformLang" is NV|BS|RT attributions.
1961 Attributes
= EFI_VARIABLE_NON_VOLATILE
| EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_RUNTIME_ACCESS
;
1963 if (StrCmp (VariableName
, EFI_PLATFORM_LANG_VARIABLE_NAME
) == 0) {
1965 // Update Lang when PlatformLangCodes/LangCodes were set.
1967 if ((mVariableModuleGlobal
->PlatformLangCodes
!= NULL
) && (mVariableModuleGlobal
->LangCodes
!= NULL
)) {
1969 // When setting PlatformLang, firstly get most matched language string from supported language codes.
1971 BestPlatformLang
= VariableGetBestLanguage (mVariableModuleGlobal
->PlatformLangCodes
, FALSE
, Data
, NULL
);
1972 if (BestPlatformLang
!= NULL
) {
1974 // Get the corresponding index in language codes.
1976 Index
= GetIndexFromSupportedLangCodes (mVariableModuleGlobal
->PlatformLangCodes
, BestPlatformLang
, FALSE
);
1979 // Get the corresponding ISO639 language tag according to RFC4646 language tag.
1981 BestLang
= GetLangFromSupportedLangCodes (mVariableModuleGlobal
->LangCodes
, Index
, TRUE
);
1984 // Check the variable space for both Lang and PlatformLang variable.
1986 VariableEntry
[0].VariableSize
= ISO_639_2_ENTRY_SIZE
+ 1;
1987 VariableEntry
[0].Guid
= &gEfiGlobalVariableGuid
;
1988 VariableEntry
[0].Name
= EFI_LANG_VARIABLE_NAME
;
1990 VariableEntry
[1].VariableSize
= AsciiStrSize (BestPlatformLang
);
1991 VariableEntry
[1].Guid
= &gEfiGlobalVariableGuid
;
1992 VariableEntry
[1].Name
= EFI_PLATFORM_LANG_VARIABLE_NAME
;
1993 if (!CheckRemainingSpaceForConsistency (VARIABLE_ATTRIBUTE_NV_BS_RT
, &VariableEntry
[0], &VariableEntry
[1], NULL
)) {
1995 // No enough variable space to set both Lang and PlatformLang successfully.
1997 Status
= EFI_OUT_OF_RESOURCES
;
2000 // Successfully convert PlatformLang to Lang, and set the BestLang value into Lang variable simultaneously.
2002 FindVariable (EFI_LANG_VARIABLE_NAME
, &gEfiGlobalVariableGuid
, &Variable
, &mVariableModuleGlobal
->VariableGlobal
, FALSE
);
2004 Status
= UpdateVariable (EFI_LANG_VARIABLE_NAME
, &gEfiGlobalVariableGuid
, BestLang
,
2005 ISO_639_2_ENTRY_SIZE
+ 1, Attributes
, 0, 0, &Variable
, NULL
);
2008 DEBUG ((EFI_D_INFO
, "Variable Driver Auto Update PlatformLang, PlatformLang:%a, Lang:%a Status: %r\n", BestPlatformLang
, BestLang
, Status
));
2012 } else if (StrCmp (VariableName
, EFI_LANG_VARIABLE_NAME
) == 0) {
2014 // Update PlatformLang when PlatformLangCodes/LangCodes were set.
2016 if ((mVariableModuleGlobal
->PlatformLangCodes
!= NULL
) && (mVariableModuleGlobal
->LangCodes
!= NULL
)) {
2018 // When setting Lang, firstly get most matched language string from supported language codes.
2020 BestLang
= VariableGetBestLanguage (mVariableModuleGlobal
->LangCodes
, TRUE
, Data
, NULL
);
2021 if (BestLang
!= NULL
) {
2023 // Get the corresponding index in language codes.
2025 Index
= GetIndexFromSupportedLangCodes (mVariableModuleGlobal
->LangCodes
, BestLang
, TRUE
);
2028 // Get the corresponding RFC4646 language tag according to ISO639 language tag.
2030 BestPlatformLang
= GetLangFromSupportedLangCodes (mVariableModuleGlobal
->PlatformLangCodes
, Index
, FALSE
);
2033 // Check the variable space for both PlatformLang and Lang variable.
2035 VariableEntry
[0].VariableSize
= AsciiStrSize (BestPlatformLang
);
2036 VariableEntry
[0].Guid
= &gEfiGlobalVariableGuid
;
2037 VariableEntry
[0].Name
= EFI_PLATFORM_LANG_VARIABLE_NAME
;
2039 VariableEntry
[1].VariableSize
= ISO_639_2_ENTRY_SIZE
+ 1;
2040 VariableEntry
[1].Guid
= &gEfiGlobalVariableGuid
;
2041 VariableEntry
[1].Name
= EFI_LANG_VARIABLE_NAME
;
2042 if (!CheckRemainingSpaceForConsistency (VARIABLE_ATTRIBUTE_NV_BS_RT
, &VariableEntry
[0], &VariableEntry
[1], NULL
)) {
2044 // No enough variable space to set both PlatformLang and Lang successfully.
2046 Status
= EFI_OUT_OF_RESOURCES
;
2049 // Successfully convert Lang to PlatformLang, and set the BestPlatformLang value into PlatformLang variable simultaneously.
2051 FindVariable (EFI_PLATFORM_LANG_VARIABLE_NAME
, &gEfiGlobalVariableGuid
, &Variable
, &mVariableModuleGlobal
->VariableGlobal
, FALSE
);
2053 Status
= UpdateVariable (EFI_PLATFORM_LANG_VARIABLE_NAME
, &gEfiGlobalVariableGuid
, BestPlatformLang
,
2054 AsciiStrSize (BestPlatformLang
), Attributes
, 0, 0, &Variable
, NULL
);
2057 DEBUG ((EFI_D_INFO
, "Variable Driver Auto Update Lang, Lang:%a, PlatformLang:%a Status: %r\n", BestLang
, BestPlatformLang
, Status
));
2062 if (SetLanguageCodes
) {
2064 // Continue to set PlatformLangCodes or LangCodes.
2073 Compare two EFI_TIME data.
2076 @param FirstTime A pointer to the first EFI_TIME data.
2077 @param SecondTime A pointer to the second EFI_TIME data.
2079 @retval TRUE The FirstTime is not later than the SecondTime.
2080 @retval FALSE The FirstTime is later than the SecondTime.
2084 VariableCompareTimeStampInternal (
2085 IN EFI_TIME
*FirstTime
,
2086 IN EFI_TIME
*SecondTime
2089 if (FirstTime
->Year
!= SecondTime
->Year
) {
2090 return (BOOLEAN
) (FirstTime
->Year
< SecondTime
->Year
);
2091 } else if (FirstTime
->Month
!= SecondTime
->Month
) {
2092 return (BOOLEAN
) (FirstTime
->Month
< SecondTime
->Month
);
2093 } else if (FirstTime
->Day
!= SecondTime
->Day
) {
2094 return (BOOLEAN
) (FirstTime
->Day
< SecondTime
->Day
);
2095 } else if (FirstTime
->Hour
!= SecondTime
->Hour
) {
2096 return (BOOLEAN
) (FirstTime
->Hour
< SecondTime
->Hour
);
2097 } else if (FirstTime
->Minute
!= SecondTime
->Minute
) {
2098 return (BOOLEAN
) (FirstTime
->Minute
< SecondTime
->Minute
);
2101 return (BOOLEAN
) (FirstTime
->Second
<= SecondTime
->Second
);
2105 Update the variable region with Variable information. If EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS is set,
2106 index of associated public key is needed.
2108 @param[in] VariableName Name of variable.
2109 @param[in] VendorGuid Guid of variable.
2110 @param[in] Data Variable data.
2111 @param[in] DataSize Size of data. 0 means delete.
2112 @param[in] Attributes Attributes of the variable.
2113 @param[in] KeyIndex Index of associated public key.
2114 @param[in] MonotonicCount Value of associated monotonic count.
2115 @param[in, out] CacheVariable The variable information which is used to keep track of variable usage.
2116 @param[in] TimeStamp Value of associated TimeStamp.
2118 @retval EFI_SUCCESS The update operation is success.
2119 @retval EFI_OUT_OF_RESOURCES Variable region is full, can not write other data into this region.
2124 IN CHAR16
*VariableName
,
2125 IN EFI_GUID
*VendorGuid
,
2128 IN UINT32 Attributes OPTIONAL
,
2129 IN UINT32 KeyIndex OPTIONAL
,
2130 IN UINT64 MonotonicCount OPTIONAL
,
2131 IN OUT VARIABLE_POINTER_TRACK
*CacheVariable
,
2132 IN EFI_TIME
*TimeStamp OPTIONAL
2136 VARIABLE_HEADER
*NextVariable
;
2139 UINTN VarNameOffset
;
2140 UINTN VarDataOffset
;
2144 EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*Fvb
;
2146 VARIABLE_POINTER_TRACK
*Variable
;
2147 VARIABLE_POINTER_TRACK NvVariable
;
2148 VARIABLE_STORE_HEADER
*VariableStoreHeader
;
2150 UINT8
*BufferForMerge
;
2151 UINTN MergedBufSize
;
2154 BOOLEAN IsCommonVariable
;
2155 BOOLEAN IsCommonUserVariable
;
2156 AUTHENTICATED_VARIABLE_HEADER
*AuthVariable
;
2158 if (mVariableModuleGlobal
->FvbInstance
== NULL
) {
2160 // The FVB protocol is not ready, so the EFI_VARIABLE_WRITE_ARCH_PROTOCOL is not installed.
2162 if ((Attributes
& EFI_VARIABLE_NON_VOLATILE
) != 0) {
2164 // Trying to update NV variable prior to the installation of EFI_VARIABLE_WRITE_ARCH_PROTOCOL
2166 DEBUG ((EFI_D_ERROR
, "Update NV variable before EFI_VARIABLE_WRITE_ARCH_PROTOCOL ready - %r\n", EFI_NOT_AVAILABLE_YET
));
2167 return EFI_NOT_AVAILABLE_YET
;
2168 } else if ((Attributes
& VARIABLE_ATTRIBUTE_AT_AW
) != 0) {
2170 // Trying to update volatile authenticated variable prior to the installation of EFI_VARIABLE_WRITE_ARCH_PROTOCOL
2171 // The authenticated variable perhaps is not initialized, just return here.
2173 DEBUG ((EFI_D_ERROR
, "Update AUTH variable before EFI_VARIABLE_WRITE_ARCH_PROTOCOL ready - %r\n", EFI_NOT_AVAILABLE_YET
));
2174 return EFI_NOT_AVAILABLE_YET
;
2178 if ((CacheVariable
->CurrPtr
== NULL
) || CacheVariable
->Volatile
) {
2179 Variable
= CacheVariable
;
2182 // Update/Delete existing NV variable.
2183 // CacheVariable points to the variable in the memory copy of Flash area
2184 // Now let Variable points to the same variable in Flash area.
2186 VariableStoreHeader
= (VARIABLE_STORE_HEADER
*) ((UINTN
) mVariableModuleGlobal
->VariableGlobal
.NonVolatileVariableBase
);
2187 Variable
= &NvVariable
;
2188 Variable
->StartPtr
= GetStartPointer (VariableStoreHeader
);
2189 Variable
->EndPtr
= GetEndPointer (VariableStoreHeader
);
2190 Variable
->CurrPtr
= (VARIABLE_HEADER
*)((UINTN
)Variable
->StartPtr
+ ((UINTN
)CacheVariable
->CurrPtr
- (UINTN
)CacheVariable
->StartPtr
));
2191 if (CacheVariable
->InDeletedTransitionPtr
!= NULL
) {
2192 Variable
->InDeletedTransitionPtr
= (VARIABLE_HEADER
*)((UINTN
)Variable
->StartPtr
+ ((UINTN
)CacheVariable
->InDeletedTransitionPtr
- (UINTN
)CacheVariable
->StartPtr
));
2194 Variable
->InDeletedTransitionPtr
= NULL
;
2196 Variable
->Volatile
= FALSE
;
2199 Fvb
= mVariableModuleGlobal
->FvbInstance
;
2202 // Tricky part: Use scratch data area at the end of volatile variable store
2203 // as a temporary storage.
2205 NextVariable
= GetEndPointer ((VARIABLE_STORE_HEADER
*) ((UINTN
) mVariableModuleGlobal
->VariableGlobal
.VolatileVariableBase
));
2206 ScratchSize
= mVariableModuleGlobal
->ScratchBufferSize
;
2207 SetMem (NextVariable
, ScratchSize
, 0xff);
2210 if (Variable
->CurrPtr
!= NULL
) {
2212 // Update/Delete existing variable.
2216 // If AtRuntime and the variable is Volatile and Runtime Access,
2217 // the volatile is ReadOnly, and SetVariable should be aborted and
2218 // return EFI_WRITE_PROTECTED.
2220 if (Variable
->Volatile
) {
2221 Status
= EFI_WRITE_PROTECTED
;
2225 // Only variable that have NV attributes can be updated/deleted in Runtime.
2227 if ((Variable
->CurrPtr
->Attributes
& EFI_VARIABLE_NON_VOLATILE
) == 0) {
2228 Status
= EFI_INVALID_PARAMETER
;
2233 // Only variable that have RT attributes can be updated/deleted in Runtime.
2235 if ((Variable
->CurrPtr
->Attributes
& EFI_VARIABLE_RUNTIME_ACCESS
) == 0) {
2236 Status
= EFI_INVALID_PARAMETER
;
2242 // Setting a data variable with no access, or zero DataSize attributes
2243 // causes it to be deleted.
2244 // When the EFI_VARIABLE_APPEND_WRITE attribute is set, DataSize of zero will
2245 // not delete the variable.
2247 if ((((Attributes
& EFI_VARIABLE_APPEND_WRITE
) == 0) && (DataSize
== 0))|| ((Attributes
& (EFI_VARIABLE_RUNTIME_ACCESS
| EFI_VARIABLE_BOOTSERVICE_ACCESS
)) == 0)) {
2248 if (Variable
->InDeletedTransitionPtr
!= NULL
) {
2250 // Both ADDED and IN_DELETED_TRANSITION variable are present,
2251 // set IN_DELETED_TRANSITION one to DELETED state first.
2253 State
= Variable
->InDeletedTransitionPtr
->State
;
2254 State
&= VAR_DELETED
;
2255 Status
= UpdateVariableStore (
2256 &mVariableModuleGlobal
->VariableGlobal
,
2260 (UINTN
) &Variable
->InDeletedTransitionPtr
->State
,
2264 if (!EFI_ERROR (Status
)) {
2265 if (!Variable
->Volatile
) {
2266 ASSERT (CacheVariable
->InDeletedTransitionPtr
!= NULL
);
2267 CacheVariable
->InDeletedTransitionPtr
->State
= State
;
2274 State
= Variable
->CurrPtr
->State
;
2275 State
&= VAR_DELETED
;
2277 Status
= UpdateVariableStore (
2278 &mVariableModuleGlobal
->VariableGlobal
,
2282 (UINTN
) &Variable
->CurrPtr
->State
,
2286 if (!EFI_ERROR (Status
)) {
2287 UpdateVariableInfo (VariableName
, VendorGuid
, Variable
->Volatile
, FALSE
, FALSE
, TRUE
, FALSE
);
2288 if (!Variable
->Volatile
) {
2289 CacheVariable
->CurrPtr
->State
= State
;
2290 FlushHobVariableToFlash (VariableName
, VendorGuid
);
2296 // If the variable is marked valid, and the same data has been passed in,
2297 // then return to the caller immediately.
2299 if (DataSizeOfVariable (Variable
->CurrPtr
) == DataSize
&&
2300 (CompareMem (Data
, GetVariableDataPtr (Variable
->CurrPtr
), DataSize
) == 0) &&
2301 ((Attributes
& EFI_VARIABLE_APPEND_WRITE
) == 0) &&
2302 (TimeStamp
== NULL
)) {
2304 // Variable content unchanged and no need to update timestamp, just return.
2306 UpdateVariableInfo (VariableName
, VendorGuid
, Variable
->Volatile
, FALSE
, TRUE
, FALSE
, FALSE
);
2307 Status
= EFI_SUCCESS
;
2309 } else if ((Variable
->CurrPtr
->State
== VAR_ADDED
) ||
2310 (Variable
->CurrPtr
->State
== (VAR_ADDED
& VAR_IN_DELETED_TRANSITION
))) {
2313 // EFI_VARIABLE_APPEND_WRITE attribute only effects for existing variable.
2315 if ((Attributes
& EFI_VARIABLE_APPEND_WRITE
) != 0) {
2317 // NOTE: From 0 to DataOffset of NextVariable is reserved for Variable Header and Name.
2318 // From DataOffset of NextVariable is to save the existing variable data.
2320 DataOffset
= GetVariableDataOffset (Variable
->CurrPtr
);
2321 BufferForMerge
= (UINT8
*) ((UINTN
) NextVariable
+ DataOffset
);
2322 CopyMem (BufferForMerge
, (UINT8
*) ((UINTN
) Variable
->CurrPtr
+ DataOffset
), DataSizeOfVariable (Variable
->CurrPtr
));
2325 // Set Max Common/Auth Variable Data Size as default MaxDataSize.
2327 if ((Attributes
& VARIABLE_ATTRIBUTE_AT_AW
) != 0) {
2328 MaxDataSize
= mVariableModuleGlobal
->MaxAuthVariableSize
- DataOffset
;
2330 MaxDataSize
= mVariableModuleGlobal
->MaxVariableSize
- DataOffset
;
2334 // Append the new data to the end of existing data.
2335 // Max Harware error record variable data size is different from common/auth variable.
2337 if ((Attributes
& EFI_VARIABLE_HARDWARE_ERROR_RECORD
) == EFI_VARIABLE_HARDWARE_ERROR_RECORD
) {
2338 MaxDataSize
= PcdGet32 (PcdMaxHardwareErrorVariableSize
) - DataOffset
;
2341 if (DataSizeOfVariable (Variable
->CurrPtr
) + DataSize
> MaxDataSize
) {
2343 // Existing data size + new data size exceed maximum variable size limitation.
2345 Status
= EFI_INVALID_PARAMETER
;
2348 CopyMem ((UINT8
*) ((UINTN
) BufferForMerge
+ DataSizeOfVariable (Variable
->CurrPtr
)), Data
, DataSize
);
2349 MergedBufSize
= DataSizeOfVariable (Variable
->CurrPtr
) + DataSize
;
2352 // BufferForMerge(from DataOffset of NextVariable) has included the merged existing and new data.
2354 Data
= BufferForMerge
;
2355 DataSize
= MergedBufSize
;
2360 // Mark the old variable as in delete transition.
2362 State
= Variable
->CurrPtr
->State
;
2363 State
&= VAR_IN_DELETED_TRANSITION
;
2365 Status
= UpdateVariableStore (
2366 &mVariableModuleGlobal
->VariableGlobal
,
2370 (UINTN
) &Variable
->CurrPtr
->State
,
2374 if (EFI_ERROR (Status
)) {
2377 if (!Variable
->Volatile
) {
2378 CacheVariable
->CurrPtr
->State
= State
;
2383 // Not found existing variable. Create a new variable.
2386 if ((DataSize
== 0) && ((Attributes
& EFI_VARIABLE_APPEND_WRITE
) != 0)) {
2387 Status
= EFI_SUCCESS
;
2392 // Make sure we are trying to create a new variable.
2393 // Setting a data variable with zero DataSize or no access attributes means to delete it.
2395 if (DataSize
== 0 || (Attributes
& (EFI_VARIABLE_RUNTIME_ACCESS
| EFI_VARIABLE_BOOTSERVICE_ACCESS
)) == 0) {
2396 Status
= EFI_NOT_FOUND
;
2401 // Only variable have NV|RT attribute can be created in Runtime.
2404 (((Attributes
& EFI_VARIABLE_RUNTIME_ACCESS
) == 0) || ((Attributes
& EFI_VARIABLE_NON_VOLATILE
) == 0))) {
2405 Status
= EFI_INVALID_PARAMETER
;
2411 // Function part - create a new variable and copy the data.
2412 // Both update a variable and create a variable will come here.
2414 NextVariable
->StartId
= VARIABLE_DATA
;
2416 // NextVariable->State = VAR_ADDED;
2418 NextVariable
->Reserved
= 0;
2419 if (mVariableModuleGlobal
->VariableGlobal
.AuthFormat
) {
2420 AuthVariable
= (AUTHENTICATED_VARIABLE_HEADER
*) NextVariable
;
2421 AuthVariable
->PubKeyIndex
= KeyIndex
;
2422 AuthVariable
->MonotonicCount
= MonotonicCount
;
2423 ZeroMem (&AuthVariable
->TimeStamp
, sizeof (EFI_TIME
));
2425 if (((Attributes
& EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS
) != 0) &&
2426 (TimeStamp
!= NULL
)) {
2427 if ((Attributes
& EFI_VARIABLE_APPEND_WRITE
) == 0) {
2428 CopyMem (&AuthVariable
->TimeStamp
, TimeStamp
, sizeof (EFI_TIME
));
2431 // In the case when the EFI_VARIABLE_APPEND_WRITE attribute is set, only
2432 // when the new TimeStamp value is later than the current timestamp associated
2433 // with the variable, we need associate the new timestamp with the updated value.
2435 if (Variable
->CurrPtr
!= NULL
) {
2436 if (VariableCompareTimeStampInternal (&(((AUTHENTICATED_VARIABLE_HEADER
*) Variable
->CurrPtr
)->TimeStamp
), TimeStamp
)) {
2437 CopyMem (&AuthVariable
->TimeStamp
, TimeStamp
, sizeof (EFI_TIME
));
2445 // The EFI_VARIABLE_APPEND_WRITE attribute will never be set in the returned
2446 // Attributes bitmask parameter of a GetVariable() call.
2448 NextVariable
->Attributes
= Attributes
& (~EFI_VARIABLE_APPEND_WRITE
);
2450 VarNameOffset
= GetVariableHeaderSize ();
2451 VarNameSize
= StrSize (VariableName
);
2453 (UINT8
*) ((UINTN
) NextVariable
+ VarNameOffset
),
2457 VarDataOffset
= VarNameOffset
+ VarNameSize
+ GET_PAD_SIZE (VarNameSize
);
2460 // If DataReady is TRUE, it means the variable data has been saved into
2461 // NextVariable during EFI_VARIABLE_APPEND_WRITE operation preparation.
2465 (UINT8
*) ((UINTN
) NextVariable
+ VarDataOffset
),
2471 CopyMem (GetVendorGuidPtr (NextVariable
), VendorGuid
, sizeof (EFI_GUID
));
2473 // There will be pad bytes after Data, the NextVariable->NameSize and
2474 // NextVariable->DataSize should not include pad size so that variable
2475 // service can get actual size in GetVariable.
2477 SetNameSizeOfVariable (NextVariable
, VarNameSize
);
2478 SetDataSizeOfVariable (NextVariable
, DataSize
);
2481 // The actual size of the variable that stores in storage should
2482 // include pad size.
2484 VarSize
= VarDataOffset
+ DataSize
+ GET_PAD_SIZE (DataSize
);
2485 if ((Attributes
& EFI_VARIABLE_NON_VOLATILE
) != 0) {
2487 // Create a nonvolatile variable.
2491 IsCommonVariable
= FALSE
;
2492 IsCommonUserVariable
= FALSE
;
2493 if ((Attributes
& EFI_VARIABLE_HARDWARE_ERROR_RECORD
) == 0) {
2494 IsCommonVariable
= TRUE
;
2495 IsCommonUserVariable
= IsUserVariable (NextVariable
);
2497 if ((((Attributes
& EFI_VARIABLE_HARDWARE_ERROR_RECORD
) != 0)
2498 && ((VarSize
+ mVariableModuleGlobal
->HwErrVariableTotalSize
) > PcdGet32 (PcdHwErrStorageSize
)))
2499 || (IsCommonVariable
&& ((VarSize
+ mVariableModuleGlobal
->CommonVariableTotalSize
) > mVariableModuleGlobal
->CommonVariableSpace
))
2500 || (IsCommonVariable
&& AtRuntime () && ((VarSize
+ mVariableModuleGlobal
->CommonVariableTotalSize
) > mVariableModuleGlobal
->CommonRuntimeVariableSpace
))
2501 || (IsCommonUserVariable
&& ((VarSize
+ mVariableModuleGlobal
->CommonUserVariableTotalSize
) > mVariableModuleGlobal
->CommonMaxUserVariableSpace
))) {
2503 if (IsCommonUserVariable
&& ((VarSize
+ mVariableModuleGlobal
->CommonUserVariableTotalSize
) > mVariableModuleGlobal
->CommonMaxUserVariableSpace
)) {
2504 RecordVarErrorFlag (VAR_ERROR_FLAG_USER_ERROR
, VariableName
, VendorGuid
, Attributes
, VarSize
);
2506 if (IsCommonVariable
&& ((VarSize
+ mVariableModuleGlobal
->CommonVariableTotalSize
) > mVariableModuleGlobal
->CommonRuntimeVariableSpace
)) {
2507 RecordVarErrorFlag (VAR_ERROR_FLAG_SYSTEM_ERROR
, VariableName
, VendorGuid
, Attributes
, VarSize
);
2509 Status
= EFI_OUT_OF_RESOURCES
;
2513 // Perform garbage collection & reclaim operation, and integrate the new variable at the same time.
2516 mVariableModuleGlobal
->VariableGlobal
.NonVolatileVariableBase
,
2517 &mVariableModuleGlobal
->NonVolatileLastVariableOffset
,
2521 HEADER_ALIGN (VarSize
)
2523 if (!EFI_ERROR (Status
)) {
2525 // The new variable has been integrated successfully during reclaiming.
2527 if (Variable
->CurrPtr
!= NULL
) {
2528 CacheVariable
->CurrPtr
= (VARIABLE_HEADER
*)((UINTN
) CacheVariable
->StartPtr
+ ((UINTN
) Variable
->CurrPtr
- (UINTN
) Variable
->StartPtr
));
2529 CacheVariable
->InDeletedTransitionPtr
= NULL
;
2531 UpdateVariableInfo (VariableName
, VendorGuid
, FALSE
, FALSE
, TRUE
, FALSE
, FALSE
);
2532 FlushHobVariableToFlash (VariableName
, VendorGuid
);
2534 if (IsCommonUserVariable
&& ((VarSize
+ mVariableModuleGlobal
->CommonUserVariableTotalSize
) > mVariableModuleGlobal
->CommonMaxUserVariableSpace
)) {
2535 RecordVarErrorFlag (VAR_ERROR_FLAG_USER_ERROR
, VariableName
, VendorGuid
, Attributes
, VarSize
);
2537 if (IsCommonVariable
&& ((VarSize
+ mVariableModuleGlobal
->CommonVariableTotalSize
) > mVariableModuleGlobal
->CommonVariableSpace
)) {
2538 RecordVarErrorFlag (VAR_ERROR_FLAG_SYSTEM_ERROR
, VariableName
, VendorGuid
, Attributes
, VarSize
);
2545 // 1. Write variable header
2546 // 2. Set variable state to header valid
2547 // 3. Write variable data
2548 // 4. Set variable state to valid
2553 CacheOffset
= mVariableModuleGlobal
->NonVolatileLastVariableOffset
;
2554 Status
= UpdateVariableStore (
2555 &mVariableModuleGlobal
->VariableGlobal
,
2559 mVariableModuleGlobal
->NonVolatileLastVariableOffset
,
2560 (UINT32
) GetVariableHeaderSize (),
2561 (UINT8
*) NextVariable
2564 if (EFI_ERROR (Status
)) {
2571 NextVariable
->State
= VAR_HEADER_VALID_ONLY
;
2572 Status
= UpdateVariableStore (
2573 &mVariableModuleGlobal
->VariableGlobal
,
2577 mVariableModuleGlobal
->NonVolatileLastVariableOffset
+ OFFSET_OF (VARIABLE_HEADER
, State
),
2579 &NextVariable
->State
2582 if (EFI_ERROR (Status
)) {
2588 Status
= UpdateVariableStore (
2589 &mVariableModuleGlobal
->VariableGlobal
,
2593 mVariableModuleGlobal
->NonVolatileLastVariableOffset
+ GetVariableHeaderSize (),
2594 (UINT32
) (VarSize
- GetVariableHeaderSize ()),
2595 (UINT8
*) NextVariable
+ GetVariableHeaderSize ()
2598 if (EFI_ERROR (Status
)) {
2604 NextVariable
->State
= VAR_ADDED
;
2605 Status
= UpdateVariableStore (
2606 &mVariableModuleGlobal
->VariableGlobal
,
2610 mVariableModuleGlobal
->NonVolatileLastVariableOffset
+ OFFSET_OF (VARIABLE_HEADER
, State
),
2612 &NextVariable
->State
2615 if (EFI_ERROR (Status
)) {
2619 mVariableModuleGlobal
->NonVolatileLastVariableOffset
+= HEADER_ALIGN (VarSize
);
2621 if ((Attributes
& EFI_VARIABLE_HARDWARE_ERROR_RECORD
) != 0) {
2622 mVariableModuleGlobal
->HwErrVariableTotalSize
+= HEADER_ALIGN (VarSize
);
2624 mVariableModuleGlobal
->CommonVariableTotalSize
+= HEADER_ALIGN (VarSize
);
2625 if (IsCommonUserVariable
) {
2626 mVariableModuleGlobal
->CommonUserVariableTotalSize
+= HEADER_ALIGN (VarSize
);
2630 // update the memory copy of Flash region.
2632 CopyMem ((UINT8
*)mNvVariableCache
+ CacheOffset
, (UINT8
*)NextVariable
, VarSize
);
2635 // Create a volatile variable.
2639 if ((UINT32
) (VarSize
+ mVariableModuleGlobal
->VolatileLastVariableOffset
) >
2640 ((VARIABLE_STORE_HEADER
*) ((UINTN
) (mVariableModuleGlobal
->VariableGlobal
.VolatileVariableBase
)))->Size
) {
2642 // Perform garbage collection & reclaim operation, and integrate the new variable at the same time.
2645 mVariableModuleGlobal
->VariableGlobal
.VolatileVariableBase
,
2646 &mVariableModuleGlobal
->VolatileLastVariableOffset
,
2650 HEADER_ALIGN (VarSize
)
2652 if (!EFI_ERROR (Status
)) {
2654 // The new variable has been integrated successfully during reclaiming.
2656 if (Variable
->CurrPtr
!= NULL
) {
2657 CacheVariable
->CurrPtr
= (VARIABLE_HEADER
*)((UINTN
) CacheVariable
->StartPtr
+ ((UINTN
) Variable
->CurrPtr
- (UINTN
) Variable
->StartPtr
));
2658 CacheVariable
->InDeletedTransitionPtr
= NULL
;
2660 UpdateVariableInfo (VariableName
, VendorGuid
, TRUE
, FALSE
, TRUE
, FALSE
, FALSE
);
2665 NextVariable
->State
= VAR_ADDED
;
2666 Status
= UpdateVariableStore (
2667 &mVariableModuleGlobal
->VariableGlobal
,
2671 mVariableModuleGlobal
->VolatileLastVariableOffset
,
2673 (UINT8
*) NextVariable
2676 if (EFI_ERROR (Status
)) {
2680 mVariableModuleGlobal
->VolatileLastVariableOffset
+= HEADER_ALIGN (VarSize
);
2684 // Mark the old variable as deleted.
2686 if (!EFI_ERROR (Status
) && Variable
->CurrPtr
!= NULL
) {
2687 if (Variable
->InDeletedTransitionPtr
!= NULL
) {
2689 // Both ADDED and IN_DELETED_TRANSITION old variable are present,
2690 // set IN_DELETED_TRANSITION one to DELETED state first.
2692 State
= Variable
->InDeletedTransitionPtr
->State
;
2693 State
&= VAR_DELETED
;
2694 Status
= UpdateVariableStore (
2695 &mVariableModuleGlobal
->VariableGlobal
,
2699 (UINTN
) &Variable
->InDeletedTransitionPtr
->State
,
2703 if (!EFI_ERROR (Status
)) {
2704 if (!Variable
->Volatile
) {
2705 ASSERT (CacheVariable
->InDeletedTransitionPtr
!= NULL
);
2706 CacheVariable
->InDeletedTransitionPtr
->State
= State
;
2713 State
= Variable
->CurrPtr
->State
;
2714 State
&= VAR_DELETED
;
2716 Status
= UpdateVariableStore (
2717 &mVariableModuleGlobal
->VariableGlobal
,
2721 (UINTN
) &Variable
->CurrPtr
->State
,
2725 if (!EFI_ERROR (Status
) && !Variable
->Volatile
) {
2726 CacheVariable
->CurrPtr
->State
= State
;
2730 if (!EFI_ERROR (Status
)) {
2731 UpdateVariableInfo (VariableName
, VendorGuid
, Volatile
, FALSE
, TRUE
, FALSE
, FALSE
);
2733 FlushHobVariableToFlash (VariableName
, VendorGuid
);
2742 Check if a Unicode character is a hexadecimal character.
2744 This function checks if a Unicode character is a
2745 hexadecimal character. The valid hexadecimal character is
2746 L'0' to L'9', L'a' to L'f', or L'A' to L'F'.
2749 @param Char The character to check against.
2751 @retval TRUE If the Char is a hexadecmial character.
2752 @retval FALSE If the Char is not a hexadecmial character.
2757 IsHexaDecimalDigitCharacter (
2761 return (BOOLEAN
) ((Char
>= L
'0' && Char
<= L
'9') || (Char
>= L
'A' && Char
<= L
'F') || (Char
>= L
'a' && Char
<= L
'f'));
2766 This code checks if variable is hardware error record variable or not.
2768 According to UEFI spec, hardware error record variable should use the EFI_HARDWARE_ERROR_VARIABLE VendorGuid
2769 and have the L"HwErrRec####" name convention, #### is a printed hex value and no 0x or h is included in the hex value.
2771 @param VariableName Pointer to variable name.
2772 @param VendorGuid Variable Vendor Guid.
2774 @retval TRUE Variable is hardware error record variable.
2775 @retval FALSE Variable is not hardware error record variable.
2780 IsHwErrRecVariable (
2781 IN CHAR16
*VariableName
,
2782 IN EFI_GUID
*VendorGuid
2785 if (!CompareGuid (VendorGuid
, &gEfiHardwareErrorVariableGuid
) ||
2786 (StrLen (VariableName
) != StrLen (L
"HwErrRec####")) ||
2787 (StrnCmp(VariableName
, L
"HwErrRec", StrLen (L
"HwErrRec")) != 0) ||
2788 !IsHexaDecimalDigitCharacter (VariableName
[0x8]) ||
2789 !IsHexaDecimalDigitCharacter (VariableName
[0x9]) ||
2790 !IsHexaDecimalDigitCharacter (VariableName
[0xA]) ||
2791 !IsHexaDecimalDigitCharacter (VariableName
[0xB])) {
2799 Mark a variable that will become read-only after leaving the DXE phase of execution.
2802 @param[in] This The VARIABLE_LOCK_PROTOCOL instance.
2803 @param[in] VariableName A pointer to the variable name that will be made read-only subsequently.
2804 @param[in] VendorGuid A pointer to the vendor GUID that will be made read-only subsequently.
2806 @retval EFI_SUCCESS The variable specified by the VariableName and the VendorGuid was marked
2807 as pending to be read-only.
2808 @retval EFI_INVALID_PARAMETER VariableName or VendorGuid is NULL.
2809 Or VariableName is an empty string.
2810 @retval EFI_ACCESS_DENIED EFI_END_OF_DXE_EVENT_GROUP_GUID or EFI_EVENT_GROUP_READY_TO_BOOT has
2811 already been signaled.
2812 @retval EFI_OUT_OF_RESOURCES There is not enough resource to hold the lock request.
2816 VariableLockRequestToLock (
2817 IN CONST EDKII_VARIABLE_LOCK_PROTOCOL
*This
,
2818 IN CHAR16
*VariableName
,
2819 IN EFI_GUID
*VendorGuid
2822 VARIABLE_ENTRY
*Entry
;
2825 VARIABLE_ENTRY
*LockedEntry
;
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 for ( Link
= GetFirstNode (&mLockedVariableList
)
2845 ; !IsNull (&mLockedVariableList
, Link
)
2846 ; Link
= GetNextNode (&mLockedVariableList
, Link
)
2848 LockedEntry
= BASE_CR (Link
, VARIABLE_ENTRY
, Link
);
2849 Name
= (CHAR16
*) ((UINTN
) LockedEntry
+ sizeof (*LockedEntry
));
2850 if (CompareGuid (&LockedEntry
->Guid
, VendorGuid
) && (StrCmp (Name
, VariableName
) == 0)) {
2855 Name
= (CHAR16
*) ((UINTN
) Entry
+ sizeof (*Entry
));
2856 StrnCpy (Name
, VariableName
, StrLen (VariableName
));
2857 CopyGuid (&Entry
->Guid
, VendorGuid
);
2858 InsertTailList (&mLockedVariableList
, &Entry
->Link
);
2861 ReleaseLockOnlyAtBootTime (&mVariableModuleGlobal
->VariableGlobal
.VariableServicesLock
);
2868 This code finds variable in storage blocks (Volatile or Non-Volatile).
2870 Caution: This function may receive untrusted input.
2871 This function may be invoked in SMM mode, and datasize is external input.
2872 This function will do basic validation, before parse the data.
2874 @param VariableName Name of Variable to be found.
2875 @param VendorGuid Variable vendor GUID.
2876 @param Attributes Attribute value of the variable found.
2877 @param DataSize Size of Data found. If size is less than the
2878 data, this value contains the required size.
2879 @param Data Data pointer.
2881 @return EFI_INVALID_PARAMETER Invalid parameter.
2882 @return EFI_SUCCESS Find the specified variable.
2883 @return EFI_NOT_FOUND Not found.
2884 @return EFI_BUFFER_TO_SMALL DataSize is too small for the result.
2889 VariableServiceGetVariable (
2890 IN CHAR16
*VariableName
,
2891 IN EFI_GUID
*VendorGuid
,
2892 OUT UINT32
*Attributes OPTIONAL
,
2893 IN OUT UINTN
*DataSize
,
2898 VARIABLE_POINTER_TRACK Variable
;
2901 if (VariableName
== NULL
|| VendorGuid
== NULL
|| DataSize
== NULL
) {
2902 return EFI_INVALID_PARAMETER
;
2905 AcquireLockOnlyAtBootTime(&mVariableModuleGlobal
->VariableGlobal
.VariableServicesLock
);
2907 Status
= FindVariable (VariableName
, VendorGuid
, &Variable
, &mVariableModuleGlobal
->VariableGlobal
, FALSE
);
2908 if (Variable
.CurrPtr
== NULL
|| EFI_ERROR (Status
)) {
2915 VarDataSize
= DataSizeOfVariable (Variable
.CurrPtr
);
2916 ASSERT (VarDataSize
!= 0);
2918 if (*DataSize
>= VarDataSize
) {
2920 Status
= EFI_INVALID_PARAMETER
;
2924 CopyMem (Data
, GetVariableDataPtr (Variable
.CurrPtr
), VarDataSize
);
2925 if (Attributes
!= NULL
) {
2926 *Attributes
= Variable
.CurrPtr
->Attributes
;
2929 *DataSize
= VarDataSize
;
2930 UpdateVariableInfo (VariableName
, VendorGuid
, Variable
.Volatile
, TRUE
, FALSE
, FALSE
, FALSE
);
2932 Status
= EFI_SUCCESS
;
2935 *DataSize
= VarDataSize
;
2936 Status
= EFI_BUFFER_TOO_SMALL
;
2941 ReleaseLockOnlyAtBootTime (&mVariableModuleGlobal
->VariableGlobal
.VariableServicesLock
);
2946 This code Finds the Next available variable.
2948 Caution: This function may receive untrusted input.
2949 This function may be invoked in SMM mode. This function will do basic validation, before parse the data.
2951 @param[in] VariableName Pointer to variable name.
2952 @param[in] VendorGuid Variable Vendor Guid.
2953 @param[out] VariablePtr Pointer to variable header address.
2955 @return EFI_SUCCESS Find the specified variable.
2956 @return EFI_NOT_FOUND Not found.
2961 VariableServiceGetNextVariableInternal (
2962 IN CHAR16
*VariableName
,
2963 IN EFI_GUID
*VendorGuid
,
2964 OUT VARIABLE_HEADER
**VariablePtr
2967 VARIABLE_STORE_TYPE Type
;
2968 VARIABLE_POINTER_TRACK Variable
;
2969 VARIABLE_POINTER_TRACK VariableInHob
;
2970 VARIABLE_POINTER_TRACK VariablePtrTrack
;
2972 VARIABLE_STORE_HEADER
*VariableStoreHeader
[VariableStoreTypeMax
];
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 GetVendorGuidPtr (Variable
.CurrPtr
),
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 GetVendorGuidPtr (Variable
.CurrPtr
),
3070 if (!EFI_ERROR (Status
)) {
3071 Variable
.CurrPtr
= GetNextVariablePtr (Variable
.CurrPtr
);
3076 *VariablePtr
= Variable
.CurrPtr
;
3077 Status
= EFI_SUCCESS
;
3082 Variable
.CurrPtr
= GetNextVariablePtr (Variable
.CurrPtr
);
3091 This code Finds the Next available variable.
3093 Caution: This function may receive untrusted input.
3094 This function may be invoked in SMM mode. This function will do basic validation, before parse the data.
3096 @param VariableNameSize Size of the variable name.
3097 @param VariableName Pointer to variable name.
3098 @param VendorGuid Variable Vendor Guid.
3100 @return EFI_INVALID_PARAMETER Invalid parameter.
3101 @return EFI_SUCCESS Find the specified variable.
3102 @return EFI_NOT_FOUND Not found.
3103 @return EFI_BUFFER_TO_SMALL DataSize is too small for the result.
3108 VariableServiceGetNextVariableName (
3109 IN OUT UINTN
*VariableNameSize
,
3110 IN OUT CHAR16
*VariableName
,
3111 IN OUT EFI_GUID
*VendorGuid
3116 VARIABLE_HEADER
*VariablePtr
;
3118 if (VariableNameSize
== NULL
|| VariableName
== NULL
|| VendorGuid
== NULL
) {
3119 return EFI_INVALID_PARAMETER
;
3122 AcquireLockOnlyAtBootTime(&mVariableModuleGlobal
->VariableGlobal
.VariableServicesLock
);
3124 Status
= VariableServiceGetNextVariableInternal (VariableName
, VendorGuid
, &VariablePtr
);
3125 if (!EFI_ERROR (Status
)) {
3126 VarNameSize
= NameSizeOfVariable (VariablePtr
);
3127 ASSERT (VarNameSize
!= 0);
3128 if (VarNameSize
<= *VariableNameSize
) {
3129 CopyMem (VariableName
, GetVariableNamePtr (VariablePtr
), VarNameSize
);
3130 CopyMem (VendorGuid
, GetVendorGuidPtr (VariablePtr
), sizeof (EFI_GUID
));
3131 Status
= EFI_SUCCESS
;
3133 Status
= EFI_BUFFER_TOO_SMALL
;
3136 *VariableNameSize
= VarNameSize
;
3139 ReleaseLockOnlyAtBootTime (&mVariableModuleGlobal
->VariableGlobal
.VariableServicesLock
);
3145 This code sets variable in storage blocks (Volatile or Non-Volatile).
3147 Caution: This function may receive untrusted input.
3148 This function may be invoked in SMM mode, and datasize and data are external input.
3149 This function will do basic validation, before parse the data.
3150 This function will parse the authentication carefully to avoid security issues, like
3151 buffer overflow, integer overflow.
3152 This function will check attribute carefully to avoid authentication bypass.
3154 @param VariableName Name of Variable to be found.
3155 @param VendorGuid Variable vendor GUID.
3156 @param Attributes Attribute value of the variable found
3157 @param DataSize Size of Data found. If size is less than the
3158 data, this value contains the required size.
3159 @param Data Data pointer.
3161 @return EFI_INVALID_PARAMETER Invalid parameter.
3162 @return EFI_SUCCESS Set successfully.
3163 @return EFI_OUT_OF_RESOURCES Resource not enough to set variable.
3164 @return EFI_NOT_FOUND Not found.
3165 @return EFI_WRITE_PROTECTED Variable is read-only.
3170 VariableServiceSetVariable (
3171 IN CHAR16
*VariableName
,
3172 IN EFI_GUID
*VendorGuid
,
3173 IN UINT32 Attributes
,
3178 VARIABLE_POINTER_TRACK Variable
;
3180 VARIABLE_HEADER
*NextVariable
;
3181 EFI_PHYSICAL_ADDRESS Point
;
3184 VARIABLE_ENTRY
*Entry
;
3188 // Check input parameters.
3190 if (VariableName
== NULL
|| VariableName
[0] == 0 || VendorGuid
== NULL
) {
3191 return EFI_INVALID_PARAMETER
;
3194 if (DataSize
!= 0 && Data
== NULL
) {
3195 return EFI_INVALID_PARAMETER
;
3199 // Check for reserverd bit in variable attribute.
3201 if ((Attributes
& (~EFI_VARIABLE_ATTRIBUTES_MASK
)) != 0) {
3202 return EFI_INVALID_PARAMETER
;
3206 // Make sure if runtime bit is set, boot service bit is set also.
3208 if ((Attributes
& (EFI_VARIABLE_RUNTIME_ACCESS
| EFI_VARIABLE_BOOTSERVICE_ACCESS
)) == EFI_VARIABLE_RUNTIME_ACCESS
) {
3209 return EFI_INVALID_PARAMETER
;
3210 } else if ((Attributes
& VARIABLE_ATTRIBUTE_AT_AW
) != 0) {
3211 if (!mVariableModuleGlobal
->VariableGlobal
.AuthSupport
) {
3213 // Not support authenticated variable write.
3215 return EFI_INVALID_PARAMETER
;
3217 } else if ((Attributes
& EFI_VARIABLE_HARDWARE_ERROR_RECORD
) != 0) {
3218 if (PcdGet32 (PcdHwErrStorageSize
) == 0) {
3220 // Not support harware error record variable variable.
3222 return EFI_INVALID_PARAMETER
;
3227 // EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS and EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS attribute
3228 // cannot be set both.
3230 if (((Attributes
& EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS
) == EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS
)
3231 && ((Attributes
& EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS
) == EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS
)) {
3232 return EFI_INVALID_PARAMETER
;
3235 if ((Attributes
& EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS
) == EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS
) {
3236 if (DataSize
< AUTHINFO_SIZE
) {
3238 // Try to write Authenticated Variable without AuthInfo.
3240 return EFI_SECURITY_VIOLATION
;
3242 PayloadSize
= DataSize
- AUTHINFO_SIZE
;
3243 } else if ((Attributes
& EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS
) == EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS
) {
3245 // Sanity check for EFI_VARIABLE_AUTHENTICATION_2 descriptor.
3247 if (DataSize
< OFFSET_OF_AUTHINFO2_CERT_DATA
||
3248 ((EFI_VARIABLE_AUTHENTICATION_2
*) Data
)->AuthInfo
.Hdr
.dwLength
> DataSize
- (OFFSET_OF (EFI_VARIABLE_AUTHENTICATION_2
, AuthInfo
)) ||
3249 ((EFI_VARIABLE_AUTHENTICATION_2
*) Data
)->AuthInfo
.Hdr
.dwLength
< OFFSET_OF (WIN_CERTIFICATE_UEFI_GUID
, CertData
)) {
3250 return EFI_SECURITY_VIOLATION
;
3252 PayloadSize
= DataSize
- AUTHINFO2_SIZE (Data
);
3254 PayloadSize
= DataSize
;
3257 if ((UINTN
)(~0) - PayloadSize
< StrSize(VariableName
)){
3259 // Prevent whole variable size overflow
3261 return EFI_INVALID_PARAMETER
;
3265 // The size of the VariableName, including the Unicode Null in bytes plus
3266 // the DataSize is limited to maximum size of PcdGet32 (PcdMaxHardwareErrorVariableSize)
3267 // bytes for HwErrRec#### variable.
3269 if ((Attributes
& EFI_VARIABLE_HARDWARE_ERROR_RECORD
) == EFI_VARIABLE_HARDWARE_ERROR_RECORD
) {
3270 if (StrSize (VariableName
) + PayloadSize
> PcdGet32 (PcdMaxHardwareErrorVariableSize
) - GetVariableHeaderSize ()) {
3271 return EFI_INVALID_PARAMETER
;
3273 if (!IsHwErrRecVariable(VariableName
, VendorGuid
)) {
3274 return EFI_INVALID_PARAMETER
;
3278 // The size of the VariableName, including the Unicode Null in bytes plus
3279 // the DataSize is limited to maximum size of Max(Auth)VariableSize bytes.
3281 if ((Attributes
& VARIABLE_ATTRIBUTE_AT_AW
) != 0) {
3282 if (StrSize (VariableName
) + PayloadSize
> mVariableModuleGlobal
->MaxAuthVariableSize
- GetVariableHeaderSize ()) {
3283 return EFI_INVALID_PARAMETER
;
3286 if (StrSize (VariableName
) + PayloadSize
> mVariableModuleGlobal
->MaxVariableSize
- GetVariableHeaderSize ()) {
3287 return EFI_INVALID_PARAMETER
;
3292 Status
= InternalVarCheckSetVariableCheck (VariableName
, VendorGuid
, Attributes
, PayloadSize
, (VOID
*) ((UINTN
) Data
+ DataSize
- PayloadSize
));
3293 if (EFI_ERROR (Status
)) {
3297 AcquireLockOnlyAtBootTime(&mVariableModuleGlobal
->VariableGlobal
.VariableServicesLock
);
3300 // Consider reentrant in MCA/INIT/NMI. It needs be reupdated.
3302 if (1 < InterlockedIncrement (&mVariableModuleGlobal
->VariableGlobal
.ReentrantState
)) {
3303 Point
= mVariableModuleGlobal
->VariableGlobal
.NonVolatileVariableBase
;
3305 // Parse non-volatile variable data and get last variable offset.
3307 NextVariable
= GetStartPointer ((VARIABLE_STORE_HEADER
*) (UINTN
) Point
);
3308 while (IsValidVariableHeader (NextVariable
, GetEndPointer ((VARIABLE_STORE_HEADER
*) (UINTN
) Point
))) {
3309 NextVariable
= GetNextVariablePtr (NextVariable
);
3311 mVariableModuleGlobal
->NonVolatileLastVariableOffset
= (UINTN
) NextVariable
- (UINTN
) Point
;
3314 if (mEndOfDxe
&& mEnableLocking
) {
3316 // Treat the variables listed in the forbidden variable list as read-only after leaving DXE phase.
3318 for ( Link
= GetFirstNode (&mLockedVariableList
)
3319 ; !IsNull (&mLockedVariableList
, Link
)
3320 ; Link
= GetNextNode (&mLockedVariableList
, Link
)
3322 Entry
= BASE_CR (Link
, VARIABLE_ENTRY
, Link
);
3323 Name
= (CHAR16
*) ((UINTN
) Entry
+ sizeof (*Entry
));
3324 if (CompareGuid (&Entry
->Guid
, VendorGuid
) && (StrCmp (Name
, VariableName
) == 0)) {
3325 Status
= EFI_WRITE_PROTECTED
;
3326 DEBUG ((EFI_D_INFO
, "[Variable]: Changing readonly variable after leaving DXE phase - %g:%s\n", VendorGuid
, VariableName
));
3333 // Check whether the input variable is already existed.
3335 Status
= FindVariable (VariableName
, VendorGuid
, &Variable
, &mVariableModuleGlobal
->VariableGlobal
, TRUE
);
3336 if (!EFI_ERROR (Status
)) {
3337 if (((Variable
.CurrPtr
->Attributes
& EFI_VARIABLE_RUNTIME_ACCESS
) == 0) && AtRuntime ()) {
3338 Status
= EFI_WRITE_PROTECTED
;
3341 if (Attributes
!= 0 && (Attributes
& (~EFI_VARIABLE_APPEND_WRITE
)) != Variable
.CurrPtr
->Attributes
) {
3343 // If a preexisting variable is rewritten with different attributes, SetVariable() shall not
3344 // modify the variable and shall return EFI_INVALID_PARAMETER. Two exceptions to this rule:
3345 // 1. No access attributes specified
3346 // 2. The only attribute differing is EFI_VARIABLE_APPEND_WRITE
3348 Status
= EFI_INVALID_PARAMETER
;
3349 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
));
3354 if (!FeaturePcdGet (PcdUefiVariableDefaultLangDeprecate
)) {
3356 // Hook the operation of setting PlatformLangCodes/PlatformLang and LangCodes/Lang.
3358 Status
= AutoUpdateLangVariable (VariableName
, Data
, DataSize
);
3359 if (EFI_ERROR (Status
)) {
3361 // The auto update operation failed, directly return to avoid inconsistency between PlatformLang and Lang.
3367 if (mVariableModuleGlobal
->VariableGlobal
.AuthSupport
) {
3368 Status
= AuthVariableLibProcessVariable (VariableName
, VendorGuid
, Data
, DataSize
, Attributes
);
3370 Status
= UpdateVariable (VariableName
, VendorGuid
, Data
, DataSize
, Attributes
, 0, 0, &Variable
, NULL
);
3374 InterlockedDecrement (&mVariableModuleGlobal
->VariableGlobal
.ReentrantState
);
3375 ReleaseLockOnlyAtBootTime (&mVariableModuleGlobal
->VariableGlobal
.VariableServicesLock
);
3377 if (!AtRuntime ()) {
3378 if (!EFI_ERROR (Status
)) {
3391 This code returns information about the EFI variables.
3393 Caution: This function may receive untrusted input.
3394 This function may be invoked in SMM mode. This function will do basic validation, before parse the data.
3396 @param Attributes Attributes bitmask to specify the type of variables
3397 on which to return information.
3398 @param MaximumVariableStorageSize Pointer to the maximum size of the storage space available
3399 for the EFI variables associated with the attributes specified.
3400 @param RemainingVariableStorageSize Pointer to the remaining size of the storage space available
3401 for EFI variables associated with the attributes specified.
3402 @param MaximumVariableSize Pointer to the maximum size of an individual EFI variables
3403 associated with the attributes specified.
3405 @return EFI_SUCCESS Query successfully.
3410 VariableServiceQueryVariableInfoInternal (
3411 IN UINT32 Attributes
,
3412 OUT UINT64
*MaximumVariableStorageSize
,
3413 OUT UINT64
*RemainingVariableStorageSize
,
3414 OUT UINT64
*MaximumVariableSize
3417 VARIABLE_HEADER
*Variable
;
3418 VARIABLE_HEADER
*NextVariable
;
3419 UINT64 VariableSize
;
3420 VARIABLE_STORE_HEADER
*VariableStoreHeader
;
3421 UINT64 CommonVariableTotalSize
;
3422 UINT64 HwErrVariableTotalSize
;
3424 VARIABLE_POINTER_TRACK VariablePtrTrack
;
3426 CommonVariableTotalSize
= 0;
3427 HwErrVariableTotalSize
= 0;
3429 if((Attributes
& EFI_VARIABLE_NON_VOLATILE
) == 0) {
3431 // Query is Volatile related.
3433 VariableStoreHeader
= (VARIABLE_STORE_HEADER
*) ((UINTN
) mVariableModuleGlobal
->VariableGlobal
.VolatileVariableBase
);
3436 // Query is Non-Volatile related.
3438 VariableStoreHeader
= mNvVariableCache
;
3442 // Now let's fill *MaximumVariableStorageSize *RemainingVariableStorageSize
3443 // with the storage size (excluding the storage header size).
3445 *MaximumVariableStorageSize
= VariableStoreHeader
->Size
- sizeof (VARIABLE_STORE_HEADER
);
3448 // Harware error record variable needs larger size.
3450 if ((Attributes
& (EFI_VARIABLE_NON_VOLATILE
| EFI_VARIABLE_HARDWARE_ERROR_RECORD
)) == (EFI_VARIABLE_NON_VOLATILE
| EFI_VARIABLE_HARDWARE_ERROR_RECORD
)) {
3451 *MaximumVariableStorageSize
= PcdGet32 (PcdHwErrStorageSize
);
3452 *MaximumVariableSize
= PcdGet32 (PcdMaxHardwareErrorVariableSize
) - GetVariableHeaderSize ();
3454 if ((Attributes
& EFI_VARIABLE_NON_VOLATILE
) != 0) {
3456 *MaximumVariableStorageSize
= mVariableModuleGlobal
->CommonRuntimeVariableSpace
;
3458 *MaximumVariableStorageSize
= mVariableModuleGlobal
->CommonVariableSpace
;
3463 // Let *MaximumVariableSize be Max(Auth)VariableSize with the exception of the variable header size.
3465 if ((Attributes
& VARIABLE_ATTRIBUTE_AT_AW
) != 0) {
3466 *MaximumVariableSize
= mVariableModuleGlobal
->MaxAuthVariableSize
- GetVariableHeaderSize ();
3468 *MaximumVariableSize
= mVariableModuleGlobal
->MaxVariableSize
- GetVariableHeaderSize ();
3473 // Point to the starting address of the variables.
3475 Variable
= GetStartPointer (VariableStoreHeader
);
3478 // Now walk through the related variable store.
3480 while (IsValidVariableHeader (Variable
, GetEndPointer (VariableStoreHeader
))) {
3481 NextVariable
= GetNextVariablePtr (Variable
);
3482 VariableSize
= (UINT64
) (UINTN
) NextVariable
- (UINT64
) (UINTN
) Variable
;
3486 // We don't take the state of the variables in mind
3487 // when calculating RemainingVariableStorageSize,
3488 // since the space occupied by variables not marked with
3489 // VAR_ADDED is not allowed to be reclaimed in Runtime.
3491 if ((Variable
->Attributes
& EFI_VARIABLE_HARDWARE_ERROR_RECORD
) == EFI_VARIABLE_HARDWARE_ERROR_RECORD
) {
3492 HwErrVariableTotalSize
+= VariableSize
;
3494 CommonVariableTotalSize
+= VariableSize
;
3498 // Only care about Variables with State VAR_ADDED, because
3499 // the space not marked as VAR_ADDED is reclaimable now.
3501 if (Variable
->State
== VAR_ADDED
) {
3502 if ((Variable
->Attributes
& EFI_VARIABLE_HARDWARE_ERROR_RECORD
) == EFI_VARIABLE_HARDWARE_ERROR_RECORD
) {
3503 HwErrVariableTotalSize
+= VariableSize
;
3505 CommonVariableTotalSize
+= VariableSize
;
3507 } else if (Variable
->State
== (VAR_IN_DELETED_TRANSITION
& VAR_ADDED
)) {
3509 // If it is a IN_DELETED_TRANSITION variable,
3510 // and there is not also a same ADDED one at the same time,
3511 // this IN_DELETED_TRANSITION variable is valid.
3513 VariablePtrTrack
.StartPtr
= GetStartPointer (VariableStoreHeader
);
3514 VariablePtrTrack
.EndPtr
= GetEndPointer (VariableStoreHeader
);
3515 Status
= FindVariableEx (
3516 GetVariableNamePtr (Variable
),
3517 GetVendorGuidPtr (Variable
),
3521 if (!EFI_ERROR (Status
) && VariablePtrTrack
.CurrPtr
->State
!= VAR_ADDED
) {
3522 if ((Variable
->Attributes
& EFI_VARIABLE_HARDWARE_ERROR_RECORD
) == EFI_VARIABLE_HARDWARE_ERROR_RECORD
) {
3523 HwErrVariableTotalSize
+= VariableSize
;
3525 CommonVariableTotalSize
+= VariableSize
;
3532 // Go to the next one.
3534 Variable
= NextVariable
;
3537 if ((Attributes
& EFI_VARIABLE_HARDWARE_ERROR_RECORD
) == EFI_VARIABLE_HARDWARE_ERROR_RECORD
){
3538 *RemainingVariableStorageSize
= *MaximumVariableStorageSize
- HwErrVariableTotalSize
;
3540 if (*MaximumVariableStorageSize
< CommonVariableTotalSize
) {
3541 *RemainingVariableStorageSize
= 0;
3543 *RemainingVariableStorageSize
= *MaximumVariableStorageSize
- CommonVariableTotalSize
;
3547 if (*RemainingVariableStorageSize
< GetVariableHeaderSize ()) {
3548 *MaximumVariableSize
= 0;
3549 } else if ((*RemainingVariableStorageSize
- GetVariableHeaderSize ()) < *MaximumVariableSize
) {
3550 *MaximumVariableSize
= *RemainingVariableStorageSize
- GetVariableHeaderSize ();
3558 This code returns information about the EFI variables.
3560 Caution: This function may receive untrusted input.
3561 This function may be invoked in SMM mode. This function will do basic validation, before parse the data.
3563 @param Attributes Attributes bitmask to specify the type of variables
3564 on which to return information.
3565 @param MaximumVariableStorageSize Pointer to the maximum size of the storage space available
3566 for the EFI variables associated with the attributes specified.
3567 @param RemainingVariableStorageSize Pointer to the remaining size of the storage space available
3568 for EFI variables associated with the attributes specified.
3569 @param MaximumVariableSize Pointer to the maximum size of an individual EFI variables
3570 associated with the attributes specified.
3572 @return EFI_INVALID_PARAMETER An invalid combination of attribute bits was supplied.
3573 @return EFI_SUCCESS Query successfully.
3574 @return EFI_UNSUPPORTED The attribute is not supported on this platform.
3579 VariableServiceQueryVariableInfo (
3580 IN UINT32 Attributes
,
3581 OUT UINT64
*MaximumVariableStorageSize
,
3582 OUT UINT64
*RemainingVariableStorageSize
,
3583 OUT UINT64
*MaximumVariableSize
3588 if(MaximumVariableStorageSize
== NULL
|| RemainingVariableStorageSize
== NULL
|| MaximumVariableSize
== NULL
|| Attributes
== 0) {
3589 return EFI_INVALID_PARAMETER
;
3592 if ((Attributes
& EFI_VARIABLE_ATTRIBUTES_MASK
) == 0) {
3594 // Make sure the Attributes combination is supported by the platform.
3596 return EFI_UNSUPPORTED
;
3597 } else if ((Attributes
& (EFI_VARIABLE_RUNTIME_ACCESS
| EFI_VARIABLE_BOOTSERVICE_ACCESS
)) == EFI_VARIABLE_RUNTIME_ACCESS
) {
3599 // Make sure if runtime bit is set, boot service bit is set also.
3601 return EFI_INVALID_PARAMETER
;
3602 } else if (AtRuntime () && ((Attributes
& EFI_VARIABLE_RUNTIME_ACCESS
) == 0)) {
3604 // Make sure RT Attribute is set if we are in Runtime phase.
3606 return EFI_INVALID_PARAMETER
;
3607 } else if ((Attributes
& (EFI_VARIABLE_NON_VOLATILE
| EFI_VARIABLE_HARDWARE_ERROR_RECORD
)) == EFI_VARIABLE_HARDWARE_ERROR_RECORD
) {
3609 // Make sure Hw Attribute is set with NV.
3611 return EFI_INVALID_PARAMETER
;
3612 } else if ((Attributes
& VARIABLE_ATTRIBUTE_AT_AW
) != 0) {
3613 if (!mVariableModuleGlobal
->VariableGlobal
.AuthSupport
) {
3615 // Not support authenticated variable write.
3617 return EFI_UNSUPPORTED
;
3619 } else if ((Attributes
& EFI_VARIABLE_HARDWARE_ERROR_RECORD
) != 0) {
3620 if (PcdGet32 (PcdHwErrStorageSize
) == 0) {
3622 // Not support harware error record variable variable.
3624 return EFI_UNSUPPORTED
;
3628 AcquireLockOnlyAtBootTime(&mVariableModuleGlobal
->VariableGlobal
.VariableServicesLock
);
3630 Status
= VariableServiceQueryVariableInfoInternal (
3632 MaximumVariableStorageSize
,
3633 RemainingVariableStorageSize
,
3637 ReleaseLockOnlyAtBootTime (&mVariableModuleGlobal
->VariableGlobal
.VariableServicesLock
);
3642 This function reclaims variable storage if free size is below the threshold.
3644 Caution: This function may be invoked at SMM mode.
3645 Care must be taken to make sure not security issue.
3654 UINTN RemainingCommonRuntimeVariableSpace
;
3655 UINTN RemainingHwErrVariableSpace
;
3656 STATIC BOOLEAN Reclaimed
;
3659 // This function will be called only once at EndOfDxe or ReadyToBoot event.
3666 Status
= EFI_SUCCESS
;
3668 if (mVariableModuleGlobal
->CommonRuntimeVariableSpace
< mVariableModuleGlobal
->CommonVariableTotalSize
) {
3669 RemainingCommonRuntimeVariableSpace
= 0;
3671 RemainingCommonRuntimeVariableSpace
= mVariableModuleGlobal
->CommonRuntimeVariableSpace
- mVariableModuleGlobal
->CommonVariableTotalSize
;
3674 RemainingHwErrVariableSpace
= PcdGet32 (PcdHwErrStorageSize
) - mVariableModuleGlobal
->HwErrVariableTotalSize
;
3677 // Check if the free area is below a threshold.
3679 if (((RemainingCommonRuntimeVariableSpace
< mVariableModuleGlobal
->MaxVariableSize
) ||
3680 (RemainingCommonRuntimeVariableSpace
< mVariableModuleGlobal
->MaxAuthVariableSize
)) ||
3681 ((PcdGet32 (PcdHwErrStorageSize
) != 0) &&
3682 (RemainingHwErrVariableSpace
< PcdGet32 (PcdMaxHardwareErrorVariableSize
)))){
3684 mVariableModuleGlobal
->VariableGlobal
.NonVolatileVariableBase
,
3685 &mVariableModuleGlobal
->NonVolatileLastVariableOffset
,
3691 ASSERT_EFI_ERROR (Status
);
3696 Get non-volatile maximum variable size.
3698 @return Non-volatile maximum variable size.
3702 GetNonVolatileMaxVariableSize (
3706 if (PcdGet32 (PcdHwErrStorageSize
) != 0) {
3707 return MAX (MAX (PcdGet32 (PcdMaxVariableSize
), PcdGet32 (PcdMaxAuthVariableSize
)),
3708 PcdGet32 (PcdMaxHardwareErrorVariableSize
));
3710 return MAX (PcdGet32 (PcdMaxVariableSize
), PcdGet32 (PcdMaxAuthVariableSize
));
3715 Init non-volatile variable store.
3717 @param[out] NvFvHeader Output pointer to non-volatile FV header address.
3719 @retval EFI_SUCCESS Function successfully executed.
3720 @retval EFI_OUT_OF_RESOURCES Fail to allocate enough memory resource.
3721 @retval EFI_VOLUME_CORRUPTED Variable Store or Firmware Volume for Variable Store is corrupted.
3725 InitNonVolatileVariableStore (
3726 OUT EFI_FIRMWARE_VOLUME_HEADER
**NvFvHeader
3729 EFI_FIRMWARE_VOLUME_HEADER
*FvHeader
;
3730 VARIABLE_HEADER
*Variable
;
3731 VARIABLE_HEADER
*NextVariable
;
3732 EFI_PHYSICAL_ADDRESS VariableStoreBase
;
3733 UINT64 VariableStoreLength
;
3735 EFI_HOB_GUID_TYPE
*GuidHob
;
3736 EFI_PHYSICAL_ADDRESS NvStorageBase
;
3737 UINT8
*NvStorageData
;
3738 UINT32 NvStorageSize
;
3739 FAULT_TOLERANT_WRITE_LAST_WRITE_DATA
*FtwLastWriteData
;
3740 UINT32 BackUpOffset
;
3742 UINT32 HwErrStorageSize
;
3743 UINT32 MaxUserNvVariableSpaceSize
;
3744 UINT32 BoottimeReservedNvVariableSpaceSize
;
3746 mVariableModuleGlobal
->FvbInstance
= NULL
;
3749 // Allocate runtime memory used for a memory copy of the FLASH region.
3750 // Keep the memory and the FLASH in sync as updates occur.
3752 NvStorageSize
= PcdGet32 (PcdFlashNvStorageVariableSize
);
3753 NvStorageData
= AllocateRuntimeZeroPool (NvStorageSize
);
3754 if (NvStorageData
== NULL
) {
3755 return EFI_OUT_OF_RESOURCES
;
3758 NvStorageBase
= (EFI_PHYSICAL_ADDRESS
) PcdGet64 (PcdFlashNvStorageVariableBase64
);
3759 if (NvStorageBase
== 0) {
3760 NvStorageBase
= (EFI_PHYSICAL_ADDRESS
) PcdGet32 (PcdFlashNvStorageVariableBase
);
3763 // Copy NV storage data to the memory buffer.
3765 CopyMem (NvStorageData
, (UINT8
*) (UINTN
) NvStorageBase
, NvStorageSize
);
3768 // Check the FTW last write data hob.
3770 GuidHob
= GetFirstGuidHob (&gEdkiiFaultTolerantWriteGuid
);
3771 if (GuidHob
!= NULL
) {
3772 FtwLastWriteData
= (FAULT_TOLERANT_WRITE_LAST_WRITE_DATA
*) GET_GUID_HOB_DATA (GuidHob
);
3773 if (FtwLastWriteData
->TargetAddress
== NvStorageBase
) {
3774 DEBUG ((EFI_D_INFO
, "Variable: NV storage is backed up in spare block: 0x%x\n", (UINTN
) FtwLastWriteData
->SpareAddress
));
3776 // Copy the backed up NV storage data to the memory buffer from spare block.
3778 CopyMem (NvStorageData
, (UINT8
*) (UINTN
) (FtwLastWriteData
->SpareAddress
), NvStorageSize
);
3779 } else if ((FtwLastWriteData
->TargetAddress
> NvStorageBase
) &&
3780 (FtwLastWriteData
->TargetAddress
< (NvStorageBase
+ NvStorageSize
))) {
3782 // Flash NV storage from the Offset is backed up in spare block.
3784 BackUpOffset
= (UINT32
) (FtwLastWriteData
->TargetAddress
- NvStorageBase
);
3785 BackUpSize
= NvStorageSize
- BackUpOffset
;
3786 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
));
3788 // Copy the partial backed up NV storage data to the memory buffer from spare block.
3790 CopyMem (NvStorageData
+ BackUpOffset
, (UINT8
*) (UINTN
) FtwLastWriteData
->SpareAddress
, BackUpSize
);
3794 FvHeader
= (EFI_FIRMWARE_VOLUME_HEADER
*) NvStorageData
;
3797 // Check if the Firmware Volume is not corrupted
3799 if ((FvHeader
->Signature
!= EFI_FVH_SIGNATURE
) || (!CompareGuid (&gEfiSystemNvDataFvGuid
, &FvHeader
->FileSystemGuid
))) {
3800 FreePool (NvStorageData
);
3801 DEBUG ((EFI_D_ERROR
, "Firmware Volume for Variable Store is corrupted\n"));
3802 return EFI_VOLUME_CORRUPTED
;
3805 VariableStoreBase
= (EFI_PHYSICAL_ADDRESS
) ((UINTN
) FvHeader
+ FvHeader
->HeaderLength
);
3806 VariableStoreLength
= (UINT64
) (NvStorageSize
- FvHeader
->HeaderLength
);
3808 mVariableModuleGlobal
->VariableGlobal
.NonVolatileVariableBase
= VariableStoreBase
;
3809 mNvVariableCache
= (VARIABLE_STORE_HEADER
*) (UINTN
) VariableStoreBase
;
3810 if (GetVariableStoreStatus (mNvVariableCache
) != EfiValid
) {
3811 FreePool (NvStorageData
);
3812 DEBUG((EFI_D_ERROR
, "Variable Store header is corrupted\n"));
3813 return EFI_VOLUME_CORRUPTED
;
3815 ASSERT(mNvVariableCache
->Size
== VariableStoreLength
);
3817 ASSERT (sizeof (VARIABLE_STORE_HEADER
) <= VariableStoreLength
);
3819 mVariableModuleGlobal
->VariableGlobal
.AuthFormat
= (BOOLEAN
)(CompareGuid (&mNvVariableCache
->Signature
, &gEfiAuthenticatedVariableGuid
));
3821 HwErrStorageSize
= PcdGet32 (PcdHwErrStorageSize
);
3822 MaxUserNvVariableSpaceSize
= PcdGet32 (PcdMaxUserNvVariableSpaceSize
);
3823 BoottimeReservedNvVariableSpaceSize
= PcdGet32 (PcdBoottimeReservedNvVariableSpaceSize
);
3826 // Note that in EdkII variable driver implementation, Hardware Error Record type variable
3827 // is stored with common variable in the same NV region. So the platform integrator should
3828 // ensure that the value of PcdHwErrStorageSize is less than the value of
3829 // (VariableStoreLength - sizeof (VARIABLE_STORE_HEADER)).
3831 ASSERT (HwErrStorageSize
< (VariableStoreLength
- sizeof (VARIABLE_STORE_HEADER
)));
3833 // Ensure that the value of PcdMaxUserNvVariableSpaceSize is less than the value of
3834 // (VariableStoreLength - sizeof (VARIABLE_STORE_HEADER)) - PcdGet32 (PcdHwErrStorageSize).
3836 ASSERT (MaxUserNvVariableSpaceSize
< (VariableStoreLength
- sizeof (VARIABLE_STORE_HEADER
) - HwErrStorageSize
));
3838 // Ensure that the value of PcdBoottimeReservedNvVariableSpaceSize is less than the value of
3839 // (VariableStoreLength - sizeof (VARIABLE_STORE_HEADER)) - PcdGet32 (PcdHwErrStorageSize).
3841 ASSERT (BoottimeReservedNvVariableSpaceSize
< (VariableStoreLength
- sizeof (VARIABLE_STORE_HEADER
) - HwErrStorageSize
));
3843 mVariableModuleGlobal
->CommonVariableSpace
= ((UINTN
) VariableStoreLength
- sizeof (VARIABLE_STORE_HEADER
) - HwErrStorageSize
);
3844 mVariableModuleGlobal
->CommonMaxUserVariableSpace
= ((MaxUserNvVariableSpaceSize
!= 0) ? MaxUserNvVariableSpaceSize
: mVariableModuleGlobal
->CommonVariableSpace
);
3845 mVariableModuleGlobal
->CommonRuntimeVariableSpace
= mVariableModuleGlobal
->CommonVariableSpace
- BoottimeReservedNvVariableSpaceSize
;
3847 DEBUG ((EFI_D_INFO
, "Variable driver common space: 0x%x 0x%x 0x%x\n", mVariableModuleGlobal
->CommonVariableSpace
, mVariableModuleGlobal
->CommonMaxUserVariableSpace
, mVariableModuleGlobal
->CommonRuntimeVariableSpace
));
3850 // The max NV variable size should be < (VariableStoreLength - sizeof (VARIABLE_STORE_HEADER)).
3852 ASSERT (GetNonVolatileMaxVariableSize () < (VariableStoreLength
- sizeof (VARIABLE_STORE_HEADER
)));
3854 mVariableModuleGlobal
->MaxVariableSize
= PcdGet32 (PcdMaxVariableSize
);
3855 mVariableModuleGlobal
->MaxAuthVariableSize
= ((PcdGet32 (PcdMaxAuthVariableSize
) != 0) ? PcdGet32 (PcdMaxAuthVariableSize
) : mVariableModuleGlobal
->MaxVariableSize
);
3858 // Parse non-volatile variable data and get last variable offset.
3860 Variable
= GetStartPointer ((VARIABLE_STORE_HEADER
*)(UINTN
)VariableStoreBase
);
3861 while (IsValidVariableHeader (Variable
, GetEndPointer ((VARIABLE_STORE_HEADER
*)(UINTN
)VariableStoreBase
))) {
3862 NextVariable
= GetNextVariablePtr (Variable
);
3863 VariableSize
= (UINTN
) NextVariable
- (UINTN
) Variable
;
3864 if ((Variable
->Attributes
& (EFI_VARIABLE_NON_VOLATILE
| EFI_VARIABLE_HARDWARE_ERROR_RECORD
)) == (EFI_VARIABLE_NON_VOLATILE
| EFI_VARIABLE_HARDWARE_ERROR_RECORD
)) {
3865 mVariableModuleGlobal
->HwErrVariableTotalSize
+= VariableSize
;
3867 mVariableModuleGlobal
->CommonVariableTotalSize
+= VariableSize
;
3870 Variable
= NextVariable
;
3872 mVariableModuleGlobal
->NonVolatileLastVariableOffset
= (UINTN
) Variable
- (UINTN
) VariableStoreBase
;
3874 *NvFvHeader
= FvHeader
;
3879 Flush the HOB variable to flash.
3881 @param[in] VariableName Name of variable has been updated or deleted.
3882 @param[in] VendorGuid Guid of variable has been updated or deleted.
3886 FlushHobVariableToFlash (
3887 IN CHAR16
*VariableName
,
3888 IN EFI_GUID
*VendorGuid
3892 VARIABLE_STORE_HEADER
*VariableStoreHeader
;
3893 VARIABLE_HEADER
*Variable
;
3900 // Flush the HOB variable to flash.
3902 if (mVariableModuleGlobal
->VariableGlobal
.HobVariableBase
!= 0) {
3903 VariableStoreHeader
= (VARIABLE_STORE_HEADER
*) (UINTN
) mVariableModuleGlobal
->VariableGlobal
.HobVariableBase
;
3905 // Set HobVariableBase to 0, it can avoid SetVariable to call back.
3907 mVariableModuleGlobal
->VariableGlobal
.HobVariableBase
= 0;
3908 for ( Variable
= GetStartPointer (VariableStoreHeader
)
3909 ; IsValidVariableHeader (Variable
, GetEndPointer (VariableStoreHeader
))
3910 ; Variable
= GetNextVariablePtr (Variable
)
3912 if (Variable
->State
!= VAR_ADDED
) {
3914 // The HOB variable has been set to DELETED state in local.
3918 ASSERT ((Variable
->Attributes
& EFI_VARIABLE_NON_VOLATILE
) != 0);
3919 if (VendorGuid
== NULL
|| VariableName
== NULL
||
3920 !CompareGuid (VendorGuid
, GetVendorGuidPtr (Variable
)) ||
3921 StrCmp (VariableName
, GetVariableNamePtr (Variable
)) != 0) {
3922 VariableData
= GetVariableDataPtr (Variable
);
3923 Status
= VariableServiceSetVariable (
3924 GetVariableNamePtr (Variable
),
3925 GetVendorGuidPtr (Variable
),
3926 Variable
->Attributes
,
3927 DataSizeOfVariable (Variable
),
3930 DEBUG ((EFI_D_INFO
, "Variable driver flush the HOB variable to flash: %g %s %r\n", GetVendorGuidPtr (Variable
), GetVariableNamePtr (Variable
), Status
));
3933 // The updated or deleted variable is matched with the HOB variable.
3934 // Don't break here because we will try to set other HOB variables
3935 // since this variable could be set successfully.
3937 Status
= EFI_SUCCESS
;
3939 if (!EFI_ERROR (Status
)) {
3941 // If set variable successful, or the updated or deleted variable is matched with the HOB variable,
3942 // set the HOB variable to DELETED state in local.
3944 DEBUG ((EFI_D_INFO
, "Variable driver set the HOB variable to DELETED state in local: %g %s\n", GetVendorGuidPtr (Variable
), GetVariableNamePtr (Variable
)));
3945 Variable
->State
&= VAR_DELETED
;
3952 // We still have HOB variable(s) not flushed in flash.
3954 mVariableModuleGlobal
->VariableGlobal
.HobVariableBase
= (EFI_PHYSICAL_ADDRESS
) (UINTN
) VariableStoreHeader
;
3957 // All HOB variables have been flushed in flash.
3959 DEBUG ((EFI_D_INFO
, "Variable driver: all HOB variables have been flushed in flash.\n"));
3960 if (!AtRuntime ()) {
3961 FreePool ((VOID
*) VariableStoreHeader
);
3969 Initializes variable write service after FTW was ready.
3971 @retval EFI_SUCCESS Function successfully executed.
3972 @retval Others Fail to initialize the variable service.
3976 VariableWriteServiceInitialize (
3981 VARIABLE_STORE_HEADER
*VariableStoreHeader
;
3984 EFI_PHYSICAL_ADDRESS VariableStoreBase
;
3985 EFI_PHYSICAL_ADDRESS NvStorageBase
;
3986 VARIABLE_ENTRY_PROPERTY
*VariableEntry
;
3988 NvStorageBase
= (EFI_PHYSICAL_ADDRESS
) PcdGet64 (PcdFlashNvStorageVariableBase64
);
3989 if (NvStorageBase
== 0) {
3990 NvStorageBase
= (EFI_PHYSICAL_ADDRESS
) PcdGet32 (PcdFlashNvStorageVariableBase
);
3992 VariableStoreBase
= NvStorageBase
+ (((EFI_FIRMWARE_VOLUME_HEADER
*)(UINTN
)(NvStorageBase
))->HeaderLength
);
3995 // Let NonVolatileVariableBase point to flash variable store base directly after FTW ready.
3997 mVariableModuleGlobal
->VariableGlobal
.NonVolatileVariableBase
= VariableStoreBase
;
3998 VariableStoreHeader
= (VARIABLE_STORE_HEADER
*)(UINTN
)VariableStoreBase
;
4001 // Check if the free area is really free.
4003 for (Index
= mVariableModuleGlobal
->NonVolatileLastVariableOffset
; Index
< VariableStoreHeader
->Size
; Index
++) {
4004 Data
= ((UINT8
*) mNvVariableCache
)[Index
];
4007 // There must be something wrong in variable store, do reclaim operation.
4010 mVariableModuleGlobal
->VariableGlobal
.NonVolatileVariableBase
,
4011 &mVariableModuleGlobal
->NonVolatileLastVariableOffset
,
4017 if (EFI_ERROR (Status
)) {
4024 FlushHobVariableToFlash (NULL
, NULL
);
4026 Status
= EFI_SUCCESS
;
4027 ZeroMem (&mContextOut
, sizeof (mContextOut
));
4028 if (mVariableModuleGlobal
->VariableGlobal
.AuthFormat
) {
4030 // Authenticated variable initialize.
4032 mContextIn
.MaxAuthVariableSize
= mVariableModuleGlobal
->MaxAuthVariableSize
- GetVariableHeaderSize ();
4033 Status
= AuthVariableLibInitialize (&mContextIn
, &mContextOut
);
4034 if (!EFI_ERROR (Status
)) {
4035 DEBUG ((EFI_D_INFO
, "Variable driver will work with auth variable support!\n"));
4036 mVariableModuleGlobal
->VariableGlobal
.AuthSupport
= TRUE
;
4037 if (mContextOut
.AuthVarEntry
!= NULL
) {
4038 for (Index
= 0; Index
< mContextOut
.AuthVarEntryCount
; Index
++) {
4039 VariableEntry
= &mContextOut
.AuthVarEntry
[Index
];
4040 Status
= InternalVarCheckVariablePropertySet (
4041 VariableEntry
->Name
,
4042 VariableEntry
->Guid
,
4043 &VariableEntry
->VariableProperty
4045 ASSERT_EFI_ERROR (Status
);
4048 } else if (Status
== EFI_UNSUPPORTED
) {
4049 DEBUG ((EFI_D_INFO
, "NOTICE - AuthVariableLibInitialize() returns %r!\n", Status
));
4050 DEBUG ((EFI_D_INFO
, "Variable driver will continue to work without auth variable support!\n"));
4051 mVariableModuleGlobal
->VariableGlobal
.AuthSupport
= FALSE
;
4052 Status
= EFI_SUCCESS
;
4056 if (!EFI_ERROR (Status
)) {
4057 for (Index
= 0; Index
< sizeof (mVariableEntryProperty
) / sizeof (mVariableEntryProperty
[0]); Index
++) {
4058 VariableEntry
= &mVariableEntryProperty
[Index
];
4059 Status
= InternalVarCheckVariablePropertySet (VariableEntry
->Name
, VariableEntry
->Guid
, &VariableEntry
->VariableProperty
);
4060 ASSERT_EFI_ERROR (Status
);
4069 Initializes variable store area for non-volatile and volatile variable.
4071 @retval EFI_SUCCESS Function successfully executed.
4072 @retval EFI_OUT_OF_RESOURCES Fail to allocate enough memory resource.
4076 VariableCommonInitialize (
4081 VARIABLE_STORE_HEADER
*VolatileVariableStore
;
4082 VARIABLE_STORE_HEADER
*VariableStoreHeader
;
4083 UINT64 VariableStoreLength
;
4085 EFI_HOB_GUID_TYPE
*GuidHob
;
4086 EFI_GUID
*VariableGuid
;
4087 EFI_FIRMWARE_VOLUME_HEADER
*NvFvHeader
;
4090 // Allocate runtime memory for variable driver global structure.
4092 mVariableModuleGlobal
= AllocateRuntimeZeroPool (sizeof (VARIABLE_MODULE_GLOBAL
));
4093 if (mVariableModuleGlobal
== NULL
) {
4094 return EFI_OUT_OF_RESOURCES
;
4097 InitializeLock (&mVariableModuleGlobal
->VariableGlobal
.VariableServicesLock
, TPL_NOTIFY
);
4100 // Init non-volatile variable store.
4102 Status
= InitNonVolatileVariableStore (&NvFvHeader
);
4103 if (EFI_ERROR (Status
)) {
4104 FreePool (mVariableModuleGlobal
);
4109 // mVariableModuleGlobal->VariableGlobal.AuthFormat
4110 // has been initialized in InitNonVolatileVariableStore().
4112 if (mVariableModuleGlobal
->VariableGlobal
.AuthFormat
) {
4113 DEBUG ((EFI_D_INFO
, "Variable driver will work with auth variable format!\n"));
4115 // Set AuthSupport to FALSE first, VariableWriteServiceInitialize() will initialize it.
4117 mVariableModuleGlobal
->VariableGlobal
.AuthSupport
= FALSE
;
4118 VariableGuid
= &gEfiAuthenticatedVariableGuid
;
4120 DEBUG ((EFI_D_INFO
, "Variable driver will work without auth variable support!\n"));
4121 mVariableModuleGlobal
->VariableGlobal
.AuthSupport
= FALSE
;
4122 VariableGuid
= &gEfiVariableGuid
;
4126 // Get HOB variable store.
4128 GuidHob
= GetFirstGuidHob (VariableGuid
);
4129 if (GuidHob
!= NULL
) {
4130 VariableStoreHeader
= GET_GUID_HOB_DATA (GuidHob
);
4131 VariableStoreLength
= (UINT64
) (GuidHob
->Header
.HobLength
- sizeof (EFI_HOB_GUID_TYPE
));
4132 if (GetVariableStoreStatus (VariableStoreHeader
) == EfiValid
) {
4133 mVariableModuleGlobal
->VariableGlobal
.HobVariableBase
= (EFI_PHYSICAL_ADDRESS
) (UINTN
) AllocateRuntimeCopyPool ((UINTN
) VariableStoreLength
, (VOID
*) VariableStoreHeader
);
4134 if (mVariableModuleGlobal
->VariableGlobal
.HobVariableBase
== 0) {
4135 FreePool (NvFvHeader
);
4136 FreePool (mVariableModuleGlobal
);
4137 return EFI_OUT_OF_RESOURCES
;
4140 DEBUG ((EFI_D_ERROR
, "HOB Variable Store header is corrupted!\n"));
4145 // Allocate memory for volatile variable store, note that there is a scratch space to store scratch data.
4147 ScratchSize
= GetNonVolatileMaxVariableSize ();
4148 mVariableModuleGlobal
->ScratchBufferSize
= ScratchSize
;
4149 VolatileVariableStore
= AllocateRuntimePool (PcdGet32 (PcdVariableStoreSize
) + ScratchSize
);
4150 if (VolatileVariableStore
== NULL
) {
4151 if (mVariableModuleGlobal
->VariableGlobal
.HobVariableBase
!= 0) {
4152 FreePool ((VOID
*) (UINTN
) mVariableModuleGlobal
->VariableGlobal
.HobVariableBase
);
4154 FreePool (NvFvHeader
);
4155 FreePool (mVariableModuleGlobal
);
4156 return EFI_OUT_OF_RESOURCES
;
4159 SetMem (VolatileVariableStore
, PcdGet32 (PcdVariableStoreSize
) + ScratchSize
, 0xff);
4162 // Initialize Variable Specific Data.
4164 mVariableModuleGlobal
->VariableGlobal
.VolatileVariableBase
= (EFI_PHYSICAL_ADDRESS
) (UINTN
) VolatileVariableStore
;
4165 mVariableModuleGlobal
->VolatileLastVariableOffset
= (UINTN
) GetStartPointer (VolatileVariableStore
) - (UINTN
) VolatileVariableStore
;
4167 CopyGuid (&VolatileVariableStore
->Signature
, VariableGuid
);
4168 VolatileVariableStore
->Size
= PcdGet32 (PcdVariableStoreSize
);
4169 VolatileVariableStore
->Format
= VARIABLE_STORE_FORMATTED
;
4170 VolatileVariableStore
->State
= VARIABLE_STORE_HEALTHY
;
4171 VolatileVariableStore
->Reserved
= 0;
4172 VolatileVariableStore
->Reserved1
= 0;
4179 Get the proper fvb handle and/or fvb protocol by the given Flash address.
4181 @param[in] Address The Flash address.
4182 @param[out] FvbHandle In output, if it is not NULL, it points to the proper FVB handle.
4183 @param[out] FvbProtocol In output, if it is not NULL, it points to the proper FVB protocol.
4187 GetFvbInfoByAddress (
4188 IN EFI_PHYSICAL_ADDRESS Address
,
4189 OUT EFI_HANDLE
*FvbHandle OPTIONAL
,
4190 OUT EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
**FvbProtocol OPTIONAL
4194 EFI_HANDLE
*HandleBuffer
;
4197 EFI_PHYSICAL_ADDRESS FvbBaseAddress
;
4198 EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*Fvb
;
4199 EFI_FVB_ATTRIBUTES_2 Attributes
;
4201 UINTN NumberOfBlocks
;
4203 HandleBuffer
= NULL
;
4205 // Get all FVB handles.
4207 Status
= GetFvbCountAndBuffer (&HandleCount
, &HandleBuffer
);
4208 if (EFI_ERROR (Status
)) {
4209 return EFI_NOT_FOUND
;
4213 // Get the FVB to access variable store.
4216 for (Index
= 0; Index
< HandleCount
; Index
+= 1, Status
= EFI_NOT_FOUND
, Fvb
= NULL
) {
4217 Status
= GetFvbByHandle (HandleBuffer
[Index
], &Fvb
);
4218 if (EFI_ERROR (Status
)) {
4219 Status
= EFI_NOT_FOUND
;
4224 // Ensure this FVB protocol supported Write operation.
4226 Status
= Fvb
->GetAttributes (Fvb
, &Attributes
);
4227 if (EFI_ERROR (Status
) || ((Attributes
& EFI_FVB2_WRITE_STATUS
) == 0)) {
4232 // Compare the address and select the right one.
4234 Status
= Fvb
->GetPhysicalAddress (Fvb
, &FvbBaseAddress
);
4235 if (EFI_ERROR (Status
)) {
4240 // Assume one FVB has one type of BlockSize.
4242 Status
= Fvb
->GetBlockSize (Fvb
, 0, &BlockSize
, &NumberOfBlocks
);
4243 if (EFI_ERROR (Status
)) {
4247 if ((Address
>= FvbBaseAddress
) && (Address
< (FvbBaseAddress
+ BlockSize
* NumberOfBlocks
))) {
4248 if (FvbHandle
!= NULL
) {
4249 *FvbHandle
= HandleBuffer
[Index
];
4251 if (FvbProtocol
!= NULL
) {
4254 Status
= EFI_SUCCESS
;
4258 FreePool (HandleBuffer
);
4261 Status
= EFI_NOT_FOUND
;