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 - 2016, Intel Corporation. All rights reserved.<BR>
20 (C) Copyright 2015 Hewlett Packard Enterprise Development LP<BR>
21 This program and the accompanying materials
22 are licensed and made available under the terms and conditions of the BSD License
23 which accompanies this distribution. The full text of the license may be found at
24 http://opensource.org/licenses/bsd-license.php
26 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
27 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
33 VARIABLE_MODULE_GLOBAL
*mVariableModuleGlobal
;
36 /// Define a memory cache that improves the search performance for a variable.
38 VARIABLE_STORE_HEADER
*mNvVariableCache
= NULL
;
41 /// Memory cache of Fv Header.
43 EFI_FIRMWARE_VOLUME_HEADER
*mNvFvHeaderCache
= NULL
;
46 /// The memory entry used for variable statistics data.
48 VARIABLE_INFO_ENTRY
*gVariableInfo
= NULL
;
51 /// The flag to indicate whether the platform has left the DXE phase of execution.
53 BOOLEAN mEndOfDxe
= FALSE
;
56 /// It indicates the var check request source.
57 /// In the implementation, DXE is regarded as untrusted, and SMM is trusted.
59 VAR_CHECK_REQUEST_SOURCE mRequestSource
= VarCheckFromUntrusted
;
62 // It will record the current boot error flag before EndOfDxe.
64 VAR_ERROR_FLAG mCurrentBootVarErrFlag
= VAR_ERROR_FLAG_NO_ERROR
;
66 VARIABLE_ENTRY_PROPERTY mVariableEntryProperty
[] = {
68 &gEdkiiVarErrorFlagGuid
,
71 VAR_CHECK_VARIABLE_PROPERTY_REVISION
,
72 VAR_CHECK_VARIABLE_PROPERTY_READ_ONLY
,
73 VARIABLE_ATTRIBUTE_NV_BS_RT
,
74 sizeof (VAR_ERROR_FLAG
),
75 sizeof (VAR_ERROR_FLAG
)
80 AUTH_VAR_LIB_CONTEXT_IN mAuthContextIn
= {
81 AUTH_VAR_LIB_CONTEXT_IN_STRUCT_VERSION
,
83 // StructSize, TO BE FILLED
87 // MaxAuthVariableSize, TO BE FILLED
90 VariableExLibFindVariable
,
91 VariableExLibFindNextVariable
,
92 VariableExLibUpdateVariable
,
93 VariableExLibGetScratchBuffer
,
94 VariableExLibCheckRemainingSpaceForConsistency
,
95 VariableExLibAtRuntime
,
98 AUTH_VAR_LIB_CONTEXT_OUT mAuthContextOut
;
102 SecureBoot Hook for auth variable update.
104 @param[in] VariableName Name of Variable to be found.
105 @param[in] VendorGuid Variable vendor GUID.
110 IN CHAR16
*VariableName
,
111 IN EFI_GUID
*VendorGuid
115 Initialization for MOR Lock Control.
117 @retval EFI_SUCEESS MorLock initialization success.
118 @return Others Some error occurs.
126 This service is an MOR/MorLock checker handler for the SetVariable().
128 @param VariableName the name of the vendor's variable, as a
129 Null-Terminated Unicode String
130 @param VendorGuid Unify identifier for vendor.
131 @param Attributes Point to memory location to return the attributes of variable. If the point
132 is NULL, the parameter would be ignored.
133 @param DataSize The size in bytes of Data-Buffer.
134 @param Data Point to the content of the variable.
136 @retval EFI_SUCCESS The MOR/MorLock check pass, and Variable driver can store the variable data.
137 @retval EFI_INVALID_PARAMETER The MOR/MorLock data or data size or attributes is not allowed for MOR variable.
138 @retval EFI_ACCESS_DENIED The MOR/MorLock is locked.
139 @retval EFI_ALREADY_STARTED The MorLock variable is handled inside this function.
140 Variable driver can just return EFI_SUCCESS.
143 SetVariableCheckHandlerMor (
144 IN CHAR16
*VariableName
,
145 IN EFI_GUID
*VendorGuid
,
146 IN UINT32 Attributes
,
152 Routine used to track statistical information about variable usage.
153 The data is stored in the EFI system table so it can be accessed later.
154 VariableInfo.efi can dump out the table. Only Boot Services variable
155 accesses are tracked by this code. The PcdVariableCollectStatistics
156 build flag controls if this feature is enabled.
158 A read that hits in the cache will have Read and Cache true for
159 the transaction. Data is allocated by this routine, but never
162 @param[in] VariableName Name of the Variable to track.
163 @param[in] VendorGuid Guid of the Variable to track.
164 @param[in] Volatile TRUE if volatile FALSE if non-volatile.
165 @param[in] Read TRUE if GetVariable() was called.
166 @param[in] Write TRUE if SetVariable() was called.
167 @param[in] Delete TRUE if deleted via SetVariable().
168 @param[in] Cache TRUE for a cache hit.
173 IN CHAR16
*VariableName
,
174 IN EFI_GUID
*VendorGuid
,
182 VARIABLE_INFO_ENTRY
*Entry
;
184 if (FeaturePcdGet (PcdVariableCollectStatistics
)) {
187 // Don't collect statistics at runtime.
191 if (gVariableInfo
== NULL
) {
193 // On the first call allocate a entry and place a pointer to it in
194 // the EFI System Table.
196 gVariableInfo
= AllocateZeroPool (sizeof (VARIABLE_INFO_ENTRY
));
197 ASSERT (gVariableInfo
!= NULL
);
199 CopyGuid (&gVariableInfo
->VendorGuid
, VendorGuid
);
200 gVariableInfo
->Name
= AllocateZeroPool (StrSize (VariableName
));
201 ASSERT (gVariableInfo
->Name
!= NULL
);
202 StrCpyS (gVariableInfo
->Name
, StrSize(VariableName
)/sizeof(CHAR16
), VariableName
);
203 gVariableInfo
->Volatile
= Volatile
;
207 for (Entry
= gVariableInfo
; Entry
!= NULL
; Entry
= Entry
->Next
) {
208 if (CompareGuid (VendorGuid
, &Entry
->VendorGuid
)) {
209 if (StrCmp (VariableName
, Entry
->Name
) == 0) {
217 Entry
->DeleteCount
++;
227 if (Entry
->Next
== NULL
) {
229 // If the entry is not in the table add it.
230 // Next iteration of the loop will fill in the data.
232 Entry
->Next
= AllocateZeroPool (sizeof (VARIABLE_INFO_ENTRY
));
233 ASSERT (Entry
->Next
!= NULL
);
235 CopyGuid (&Entry
->Next
->VendorGuid
, VendorGuid
);
236 Entry
->Next
->Name
= AllocateZeroPool (StrSize (VariableName
));
237 ASSERT (Entry
->Next
->Name
!= NULL
);
238 StrCpyS (Entry
->Next
->Name
, StrSize(VariableName
)/sizeof(CHAR16
), VariableName
);
239 Entry
->Next
->Volatile
= Volatile
;
249 This code checks if variable header is valid or not.
251 @param Variable Pointer to the Variable Header.
252 @param VariableStoreEnd Pointer to the Variable Store End.
254 @retval TRUE Variable header is valid.
255 @retval FALSE Variable header is not valid.
259 IsValidVariableHeader (
260 IN VARIABLE_HEADER
*Variable
,
261 IN VARIABLE_HEADER
*VariableStoreEnd
264 if ((Variable
== NULL
) || (Variable
>= VariableStoreEnd
) || (Variable
->StartId
!= VARIABLE_DATA
)) {
266 // Variable is NULL or has reached the end of variable store,
267 // or the StartId is not correct.
278 This function writes data to the FWH at the correct LBA even if the LBAs
281 @param Global Pointer to VARAIBLE_GLOBAL structure.
282 @param Volatile Point out the Variable is Volatile or Non-Volatile.
283 @param SetByIndex TRUE if target pointer is given as index.
284 FALSE if target pointer is absolute.
285 @param Fvb Pointer to the writable FVB protocol.
286 @param DataPtrIndex Pointer to the Data from the end of VARIABLE_STORE_HEADER
288 @param DataSize Size of data to be written.
289 @param Buffer Pointer to the buffer from which data is written.
291 @retval EFI_INVALID_PARAMETER Parameters not valid.
292 @retval EFI_SUCCESS Variable store successfully updated.
296 UpdateVariableStore (
297 IN VARIABLE_GLOBAL
*Global
,
299 IN BOOLEAN SetByIndex
,
300 IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*Fvb
,
301 IN UINTN DataPtrIndex
,
306 EFI_FV_BLOCK_MAP_ENTRY
*PtrBlockMapEntry
;
314 EFI_FIRMWARE_VOLUME_HEADER
*FwVolHeader
;
315 VARIABLE_STORE_HEADER
*VolatileBase
;
316 EFI_PHYSICAL_ADDRESS FvVolHdr
;
317 EFI_PHYSICAL_ADDRESS DataPtr
;
321 DataPtr
= DataPtrIndex
;
324 // Check if the Data is Volatile.
328 return EFI_INVALID_PARAMETER
;
330 Status
= Fvb
->GetPhysicalAddress(Fvb
, &FvVolHdr
);
331 ASSERT_EFI_ERROR (Status
);
333 FwVolHeader
= (EFI_FIRMWARE_VOLUME_HEADER
*) ((UINTN
) FvVolHdr
);
335 // Data Pointer should point to the actual Address where data is to be
339 DataPtr
+= mVariableModuleGlobal
->VariableGlobal
.NonVolatileVariableBase
;
342 if ((DataPtr
+ DataSize
) >= ((EFI_PHYSICAL_ADDRESS
) (UINTN
) ((UINT8
*) FwVolHeader
+ FwVolHeader
->FvLength
))) {
343 return EFI_INVALID_PARAMETER
;
347 // Data Pointer should point to the actual Address where data is to be
350 VolatileBase
= (VARIABLE_STORE_HEADER
*) ((UINTN
) mVariableModuleGlobal
->VariableGlobal
.VolatileVariableBase
);
352 DataPtr
+= mVariableModuleGlobal
->VariableGlobal
.VolatileVariableBase
;
355 if ((DataPtr
+ DataSize
) >= ((UINTN
) ((UINT8
*) VolatileBase
+ VolatileBase
->Size
))) {
356 return EFI_INVALID_PARAMETER
;
360 // If Volatile Variable just do a simple mem copy.
362 CopyMem ((UINT8
*)(UINTN
)DataPtr
, Buffer
, DataSize
);
367 // If we are here we are dealing with Non-Volatile Variables.
369 LinearOffset
= (UINTN
) FwVolHeader
;
370 CurrWritePtr
= (UINTN
) DataPtr
;
371 CurrWriteSize
= DataSize
;
375 if (CurrWritePtr
< LinearOffset
) {
376 return EFI_INVALID_PARAMETER
;
379 for (PtrBlockMapEntry
= mNvFvHeaderCache
->BlockMap
; PtrBlockMapEntry
->NumBlocks
!= 0; PtrBlockMapEntry
++) {
380 for (BlockIndex2
= 0; BlockIndex2
< PtrBlockMapEntry
->NumBlocks
; BlockIndex2
++) {
382 // Check to see if the Variable Writes are spanning through multiple
385 if ((CurrWritePtr
>= LinearOffset
) && (CurrWritePtr
< LinearOffset
+ PtrBlockMapEntry
->Length
)) {
386 if ((CurrWritePtr
+ CurrWriteSize
) <= (LinearOffset
+ PtrBlockMapEntry
->Length
)) {
387 Status
= Fvb
->Write (
390 (UINTN
) (CurrWritePtr
- LinearOffset
),
396 Size
= (UINT32
) (LinearOffset
+ PtrBlockMapEntry
->Length
- CurrWritePtr
);
397 Status
= Fvb
->Write (
400 (UINTN
) (CurrWritePtr
- LinearOffset
),
404 if (EFI_ERROR (Status
)) {
408 CurrWritePtr
= LinearOffset
+ PtrBlockMapEntry
->Length
;
409 CurrBuffer
= CurrBuffer
+ Size
;
410 CurrWriteSize
= CurrWriteSize
- Size
;
414 LinearOffset
+= PtrBlockMapEntry
->Length
;
425 This code gets the current status of Variable Store.
427 @param VarStoreHeader Pointer to the Variable Store Header.
429 @retval EfiRaw Variable store status is raw.
430 @retval EfiValid Variable store status is valid.
431 @retval EfiInvalid Variable store status is invalid.
434 VARIABLE_STORE_STATUS
435 GetVariableStoreStatus (
436 IN VARIABLE_STORE_HEADER
*VarStoreHeader
439 if ((CompareGuid (&VarStoreHeader
->Signature
, &gEfiAuthenticatedVariableGuid
) ||
440 CompareGuid (&VarStoreHeader
->Signature
, &gEfiVariableGuid
)) &&
441 VarStoreHeader
->Format
== VARIABLE_STORE_FORMATTED
&&
442 VarStoreHeader
->State
== VARIABLE_STORE_HEALTHY
446 } else if (((UINT32
*)(&VarStoreHeader
->Signature
))[0] == 0xffffffff &&
447 ((UINT32
*)(&VarStoreHeader
->Signature
))[1] == 0xffffffff &&
448 ((UINT32
*)(&VarStoreHeader
->Signature
))[2] == 0xffffffff &&
449 ((UINT32
*)(&VarStoreHeader
->Signature
))[3] == 0xffffffff &&
450 VarStoreHeader
->Size
== 0xffffffff &&
451 VarStoreHeader
->Format
== 0xff &&
452 VarStoreHeader
->State
== 0xff
462 This code gets the size of variable header.
464 @return Size of variable header in bytes in type UINTN.
468 GetVariableHeaderSize (
474 if (mVariableModuleGlobal
->VariableGlobal
.AuthFormat
) {
475 Value
= sizeof (AUTHENTICATED_VARIABLE_HEADER
);
477 Value
= sizeof (VARIABLE_HEADER
);
485 This code gets the size of name of variable.
487 @param Variable Pointer to the Variable Header.
489 @return UINTN Size of variable in bytes.
494 IN VARIABLE_HEADER
*Variable
497 AUTHENTICATED_VARIABLE_HEADER
*AuthVariable
;
499 AuthVariable
= (AUTHENTICATED_VARIABLE_HEADER
*) Variable
;
500 if (mVariableModuleGlobal
->VariableGlobal
.AuthFormat
) {
501 if (AuthVariable
->State
== (UINT8
) (-1) ||
502 AuthVariable
->DataSize
== (UINT32
) (-1) ||
503 AuthVariable
->NameSize
== (UINT32
) (-1) ||
504 AuthVariable
->Attributes
== (UINT32
) (-1)) {
507 return (UINTN
) AuthVariable
->NameSize
;
509 if (Variable
->State
== (UINT8
) (-1) ||
510 Variable
->DataSize
== (UINT32
) (-1) ||
511 Variable
->NameSize
== (UINT32
) (-1) ||
512 Variable
->Attributes
== (UINT32
) (-1)) {
515 return (UINTN
) Variable
->NameSize
;
520 This code sets the size of name of variable.
522 @param[in] Variable Pointer to the Variable Header.
523 @param[in] NameSize Name size to set.
527 SetNameSizeOfVariable (
528 IN VARIABLE_HEADER
*Variable
,
532 AUTHENTICATED_VARIABLE_HEADER
*AuthVariable
;
534 AuthVariable
= (AUTHENTICATED_VARIABLE_HEADER
*) Variable
;
535 if (mVariableModuleGlobal
->VariableGlobal
.AuthFormat
) {
536 AuthVariable
->NameSize
= (UINT32
) NameSize
;
538 Variable
->NameSize
= (UINT32
) NameSize
;
544 This code gets the size of variable data.
546 @param Variable Pointer to the Variable Header.
548 @return Size of variable in bytes.
553 IN VARIABLE_HEADER
*Variable
556 AUTHENTICATED_VARIABLE_HEADER
*AuthVariable
;
558 AuthVariable
= (AUTHENTICATED_VARIABLE_HEADER
*) Variable
;
559 if (mVariableModuleGlobal
->VariableGlobal
.AuthFormat
) {
560 if (AuthVariable
->State
== (UINT8
) (-1) ||
561 AuthVariable
->DataSize
== (UINT32
) (-1) ||
562 AuthVariable
->NameSize
== (UINT32
) (-1) ||
563 AuthVariable
->Attributes
== (UINT32
) (-1)) {
566 return (UINTN
) AuthVariable
->DataSize
;
568 if (Variable
->State
== (UINT8
) (-1) ||
569 Variable
->DataSize
== (UINT32
) (-1) ||
570 Variable
->NameSize
== (UINT32
) (-1) ||
571 Variable
->Attributes
== (UINT32
) (-1)) {
574 return (UINTN
) Variable
->DataSize
;
579 This code sets the size of variable data.
581 @param[in] Variable Pointer to the Variable Header.
582 @param[in] DataSize Data size to set.
586 SetDataSizeOfVariable (
587 IN VARIABLE_HEADER
*Variable
,
591 AUTHENTICATED_VARIABLE_HEADER
*AuthVariable
;
593 AuthVariable
= (AUTHENTICATED_VARIABLE_HEADER
*) Variable
;
594 if (mVariableModuleGlobal
->VariableGlobal
.AuthFormat
) {
595 AuthVariable
->DataSize
= (UINT32
) DataSize
;
597 Variable
->DataSize
= (UINT32
) DataSize
;
603 This code gets the pointer to the variable name.
605 @param Variable Pointer to the Variable Header.
607 @return Pointer to Variable Name which is Unicode encoding.
612 IN VARIABLE_HEADER
*Variable
615 return (CHAR16
*) ((UINTN
) Variable
+ GetVariableHeaderSize ());
619 This code gets the pointer to the variable guid.
621 @param Variable Pointer to the Variable Header.
623 @return A EFI_GUID* pointer to Vendor Guid.
628 IN VARIABLE_HEADER
*Variable
631 AUTHENTICATED_VARIABLE_HEADER
*AuthVariable
;
633 AuthVariable
= (AUTHENTICATED_VARIABLE_HEADER
*) Variable
;
634 if (mVariableModuleGlobal
->VariableGlobal
.AuthFormat
) {
635 return &AuthVariable
->VendorGuid
;
637 return &Variable
->VendorGuid
;
643 This code gets the pointer to the variable data.
645 @param Variable Pointer to the Variable Header.
647 @return Pointer to Variable Data.
652 IN VARIABLE_HEADER
*Variable
658 // Be careful about pad size for alignment.
660 Value
= (UINTN
) GetVariableNamePtr (Variable
);
661 Value
+= NameSizeOfVariable (Variable
);
662 Value
+= GET_PAD_SIZE (NameSizeOfVariable (Variable
));
664 return (UINT8
*) Value
;
668 This code gets the variable data offset related to variable header.
670 @param Variable Pointer to the Variable Header.
672 @return Variable Data offset.
676 GetVariableDataOffset (
677 IN VARIABLE_HEADER
*Variable
683 // Be careful about pad size for alignment
685 Value
= GetVariableHeaderSize ();
686 Value
+= NameSizeOfVariable (Variable
);
687 Value
+= GET_PAD_SIZE (NameSizeOfVariable (Variable
));
694 This code gets the pointer to the next variable header.
696 @param Variable Pointer to the Variable Header.
698 @return Pointer to next variable header.
703 IN VARIABLE_HEADER
*Variable
708 Value
= (UINTN
) GetVariableDataPtr (Variable
);
709 Value
+= DataSizeOfVariable (Variable
);
710 Value
+= GET_PAD_SIZE (DataSizeOfVariable (Variable
));
713 // Be careful about pad size for alignment.
715 return (VARIABLE_HEADER
*) HEADER_ALIGN (Value
);
720 Gets the pointer to the first variable header in given variable store area.
722 @param VarStoreHeader Pointer to the Variable Store Header.
724 @return Pointer to the first variable header.
729 IN VARIABLE_STORE_HEADER
*VarStoreHeader
733 // The end of variable store.
735 return (VARIABLE_HEADER
*) HEADER_ALIGN (VarStoreHeader
+ 1);
740 Gets the pointer to the end of the variable storage area.
742 This function gets pointer to the end of the variable storage
743 area, according to the input variable store header.
745 @param VarStoreHeader Pointer to the Variable Store Header.
747 @return Pointer to the end of the variable storage area.
752 IN VARIABLE_STORE_HEADER
*VarStoreHeader
756 // The end of variable store
758 return (VARIABLE_HEADER
*) HEADER_ALIGN ((UINTN
) VarStoreHeader
+ VarStoreHeader
->Size
);
762 Record variable error flag.
764 @param[in] Flag Variable error flag to record.
765 @param[in] VariableName Name of variable.
766 @param[in] VendorGuid Guid of variable.
767 @param[in] Attributes Attributes of the variable.
768 @param[in] VariableSize Size of the variable.
773 IN VAR_ERROR_FLAG Flag
,
774 IN CHAR16
*VariableName
,
775 IN EFI_GUID
*VendorGuid
,
776 IN UINT32 Attributes
,
777 IN UINTN VariableSize
781 VARIABLE_POINTER_TRACK Variable
;
782 VAR_ERROR_FLAG
*VarErrFlag
;
783 VAR_ERROR_FLAG TempFlag
;
786 DEBUG ((EFI_D_ERROR
, "RecordVarErrorFlag (0x%02x) %s:%g - 0x%08x - 0x%x\n", Flag
, VariableName
, VendorGuid
, Attributes
, VariableSize
));
787 if (Flag
== VAR_ERROR_FLAG_SYSTEM_ERROR
) {
789 DEBUG ((EFI_D_ERROR
, "CommonRuntimeVariableSpace = 0x%x - CommonVariableTotalSize = 0x%x\n", mVariableModuleGlobal
->CommonRuntimeVariableSpace
, mVariableModuleGlobal
->CommonVariableTotalSize
));
791 DEBUG ((EFI_D_ERROR
, "CommonVariableSpace = 0x%x - CommonVariableTotalSize = 0x%x\n", mVariableModuleGlobal
->CommonVariableSpace
, mVariableModuleGlobal
->CommonVariableTotalSize
));
794 DEBUG ((EFI_D_ERROR
, "CommonMaxUserVariableSpace = 0x%x - CommonUserVariableTotalSize = 0x%x\n", mVariableModuleGlobal
->CommonMaxUserVariableSpace
, mVariableModuleGlobal
->CommonUserVariableTotalSize
));
800 // Before EndOfDxe, just record the current boot variable error flag to local variable,
801 // and leave the variable error flag in NV flash as the last boot variable error flag.
802 // After EndOfDxe in InitializeVarErrorFlag (), the variable error flag in NV flash
803 // will be initialized to this local current boot variable error flag.
805 mCurrentBootVarErrFlag
&= Flag
;
810 // Record error flag (it should have be initialized).
812 Status
= FindVariable (
814 &gEdkiiVarErrorFlagGuid
,
816 &mVariableModuleGlobal
->VariableGlobal
,
819 if (!EFI_ERROR (Status
)) {
820 VarErrFlag
= (VAR_ERROR_FLAG
*) GetVariableDataPtr (Variable
.CurrPtr
);
821 TempFlag
= *VarErrFlag
;
823 if (TempFlag
== *VarErrFlag
) {
826 Status
= UpdateVariableStore (
827 &mVariableModuleGlobal
->VariableGlobal
,
830 mVariableModuleGlobal
->FvbInstance
,
831 (UINTN
) VarErrFlag
- (UINTN
) mNvVariableCache
+ (UINTN
) mVariableModuleGlobal
->VariableGlobal
.NonVolatileVariableBase
,
835 if (!EFI_ERROR (Status
)) {
837 // Update the data in NV cache.
839 *VarErrFlag
= TempFlag
;
845 Initialize variable error flag.
847 Before EndOfDxe, the variable indicates the last boot variable error flag,
848 then it means the last boot variable error flag must be got before EndOfDxe.
849 After EndOfDxe, the variable indicates the current boot variable error flag,
850 then it means the current boot variable error flag must be got after EndOfDxe.
854 InitializeVarErrorFlag (
859 VARIABLE_POINTER_TRACK Variable
;
861 VAR_ERROR_FLAG VarErrFlag
;
867 Flag
= mCurrentBootVarErrFlag
;
868 DEBUG ((EFI_D_INFO
, "Initialize variable error flag (%02x)\n", Flag
));
870 Status
= FindVariable (
872 &gEdkiiVarErrorFlagGuid
,
874 &mVariableModuleGlobal
->VariableGlobal
,
877 if (!EFI_ERROR (Status
)) {
878 VarErrFlag
= *((VAR_ERROR_FLAG
*) GetVariableDataPtr (Variable
.CurrPtr
));
879 if (VarErrFlag
== Flag
) {
886 &gEdkiiVarErrorFlagGuid
,
889 VARIABLE_ATTRIBUTE_NV_BS_RT
,
900 @param[in] Variable Pointer to variable header.
902 @retval TRUE User variable.
903 @retval FALSE System variable.
908 IN VARIABLE_HEADER
*Variable
911 VAR_CHECK_VARIABLE_PROPERTY Property
;
914 // Only after End Of Dxe, the variables belong to system variable are fixed.
915 // If PcdMaxUserNvStorageVariableSize is 0, it means user variable share the same NV storage with system variable,
916 // then no need to check if the variable is user variable or not specially.
918 if (mEndOfDxe
&& (mVariableModuleGlobal
->CommonMaxUserVariableSpace
!= mVariableModuleGlobal
->CommonVariableSpace
)) {
919 if (VarCheckLibVariablePropertyGet (GetVariableNamePtr (Variable
), GetVendorGuidPtr (Variable
), &Property
) == EFI_NOT_FOUND
) {
927 Calculate common user variable total size.
931 CalculateCommonUserVariableTotalSize (
935 VARIABLE_HEADER
*Variable
;
936 VARIABLE_HEADER
*NextVariable
;
938 VAR_CHECK_VARIABLE_PROPERTY Property
;
941 // Only after End Of Dxe, the variables belong to system variable are fixed.
942 // If PcdMaxUserNvStorageVariableSize is 0, it means user variable share the same NV storage with system variable,
943 // then no need to calculate the common user variable total size specially.
945 if (mEndOfDxe
&& (mVariableModuleGlobal
->CommonMaxUserVariableSpace
!= mVariableModuleGlobal
->CommonVariableSpace
)) {
946 Variable
= GetStartPointer (mNvVariableCache
);
947 while (IsValidVariableHeader (Variable
, GetEndPointer (mNvVariableCache
))) {
948 NextVariable
= GetNextVariablePtr (Variable
);
949 VariableSize
= (UINTN
) NextVariable
- (UINTN
) Variable
;
950 if ((Variable
->Attributes
& EFI_VARIABLE_HARDWARE_ERROR_RECORD
) != EFI_VARIABLE_HARDWARE_ERROR_RECORD
) {
951 if (VarCheckLibVariablePropertyGet (GetVariableNamePtr (Variable
), GetVendorGuidPtr (Variable
), &Property
) == EFI_NOT_FOUND
) {
953 // No property, it is user variable.
955 mVariableModuleGlobal
->CommonUserVariableTotalSize
+= VariableSize
;
959 Variable
= NextVariable
;
965 Initialize variable quota.
969 InitializeVariableQuota (
977 InitializeVarErrorFlag ();
978 CalculateCommonUserVariableTotalSize ();
983 Variable store garbage collection and reclaim operation.
985 @param[in] VariableBase Base address of variable store.
986 @param[out] LastVariableOffset Offset of last variable.
987 @param[in] IsVolatile The variable store is volatile or not;
988 if it is non-volatile, need FTW.
989 @param[in, out] UpdatingPtrTrack Pointer to updating variable pointer track structure.
990 @param[in] NewVariable Pointer to new variable.
991 @param[in] NewVariableSize New variable size.
993 @return EFI_SUCCESS Reclaim operation has finished successfully.
994 @return EFI_OUT_OF_RESOURCES No enough memory resources or variable space.
995 @return Others Unexpect error happened during reclaim operation.
1000 IN EFI_PHYSICAL_ADDRESS VariableBase
,
1001 OUT UINTN
*LastVariableOffset
,
1002 IN BOOLEAN IsVolatile
,
1003 IN OUT VARIABLE_POINTER_TRACK
*UpdatingPtrTrack
,
1004 IN VARIABLE_HEADER
*NewVariable
,
1005 IN UINTN NewVariableSize
1008 VARIABLE_HEADER
*Variable
;
1009 VARIABLE_HEADER
*AddedVariable
;
1010 VARIABLE_HEADER
*NextVariable
;
1011 VARIABLE_HEADER
*NextAddedVariable
;
1012 VARIABLE_STORE_HEADER
*VariableStoreHeader
;
1014 UINTN MaximumBufferSize
;
1022 UINTN CommonVariableTotalSize
;
1023 UINTN CommonUserVariableTotalSize
;
1024 UINTN HwErrVariableTotalSize
;
1025 VARIABLE_HEADER
*UpdatingVariable
;
1026 VARIABLE_HEADER
*UpdatingInDeletedTransition
;
1028 UpdatingVariable
= NULL
;
1029 UpdatingInDeletedTransition
= NULL
;
1030 if (UpdatingPtrTrack
!= NULL
) {
1031 UpdatingVariable
= UpdatingPtrTrack
->CurrPtr
;
1032 UpdatingInDeletedTransition
= UpdatingPtrTrack
->InDeletedTransitionPtr
;
1035 VariableStoreHeader
= (VARIABLE_STORE_HEADER
*) ((UINTN
) VariableBase
);
1037 CommonVariableTotalSize
= 0;
1038 CommonUserVariableTotalSize
= 0;
1039 HwErrVariableTotalSize
= 0;
1043 // Start Pointers for the variable.
1045 Variable
= GetStartPointer (VariableStoreHeader
);
1046 MaximumBufferSize
= sizeof (VARIABLE_STORE_HEADER
);
1048 while (IsValidVariableHeader (Variable
, GetEndPointer (VariableStoreHeader
))) {
1049 NextVariable
= GetNextVariablePtr (Variable
);
1050 if ((Variable
->State
== VAR_ADDED
|| Variable
->State
== (VAR_IN_DELETED_TRANSITION
& VAR_ADDED
)) &&
1051 Variable
!= UpdatingVariable
&&
1052 Variable
!= UpdatingInDeletedTransition
1054 VariableSize
= (UINTN
) NextVariable
- (UINTN
) Variable
;
1055 MaximumBufferSize
+= VariableSize
;
1058 Variable
= NextVariable
;
1061 if (NewVariable
!= NULL
) {
1063 // Add the new variable size.
1065 MaximumBufferSize
+= NewVariableSize
;
1069 // Reserve the 1 Bytes with Oxff to identify the
1070 // end of the variable buffer.
1072 MaximumBufferSize
+= 1;
1073 ValidBuffer
= AllocatePool (MaximumBufferSize
);
1074 if (ValidBuffer
== NULL
) {
1075 return EFI_OUT_OF_RESOURCES
;
1079 // For NV variable reclaim, don't allocate pool here and just use mNvVariableCache
1080 // as the buffer to reduce SMRAM consumption for SMM variable driver.
1082 MaximumBufferSize
= mNvVariableCache
->Size
;
1083 ValidBuffer
= (UINT8
*) mNvVariableCache
;
1086 SetMem (ValidBuffer
, MaximumBufferSize
, 0xff);
1089 // Copy variable store header.
1091 CopyMem (ValidBuffer
, VariableStoreHeader
, sizeof (VARIABLE_STORE_HEADER
));
1092 CurrPtr
= (UINT8
*) GetStartPointer ((VARIABLE_STORE_HEADER
*) ValidBuffer
);
1095 // Reinstall all ADDED variables as long as they are not identical to Updating Variable.
1097 Variable
= GetStartPointer (VariableStoreHeader
);
1098 while (IsValidVariableHeader (Variable
, GetEndPointer (VariableStoreHeader
))) {
1099 NextVariable
= GetNextVariablePtr (Variable
);
1100 if (Variable
!= UpdatingVariable
&& Variable
->State
== VAR_ADDED
) {
1101 VariableSize
= (UINTN
) NextVariable
- (UINTN
) Variable
;
1102 CopyMem (CurrPtr
, (UINT8
*) Variable
, VariableSize
);
1103 CurrPtr
+= VariableSize
;
1104 if ((!IsVolatile
) && ((Variable
->Attributes
& EFI_VARIABLE_HARDWARE_ERROR_RECORD
) == EFI_VARIABLE_HARDWARE_ERROR_RECORD
)) {
1105 HwErrVariableTotalSize
+= VariableSize
;
1106 } else if ((!IsVolatile
) && ((Variable
->Attributes
& EFI_VARIABLE_HARDWARE_ERROR_RECORD
) != EFI_VARIABLE_HARDWARE_ERROR_RECORD
)) {
1107 CommonVariableTotalSize
+= VariableSize
;
1108 if (IsUserVariable (Variable
)) {
1109 CommonUserVariableTotalSize
+= VariableSize
;
1113 Variable
= NextVariable
;
1117 // Reinstall all in delete transition variables.
1119 Variable
= GetStartPointer (VariableStoreHeader
);
1120 while (IsValidVariableHeader (Variable
, GetEndPointer (VariableStoreHeader
))) {
1121 NextVariable
= GetNextVariablePtr (Variable
);
1122 if (Variable
!= UpdatingVariable
&& Variable
!= UpdatingInDeletedTransition
&& Variable
->State
== (VAR_IN_DELETED_TRANSITION
& VAR_ADDED
)) {
1125 // Buffer has cached all ADDED variable.
1126 // Per IN_DELETED variable, we have to guarantee that
1127 // no ADDED one in previous buffer.
1131 AddedVariable
= GetStartPointer ((VARIABLE_STORE_HEADER
*) ValidBuffer
);
1132 while (IsValidVariableHeader (AddedVariable
, GetEndPointer ((VARIABLE_STORE_HEADER
*) ValidBuffer
))) {
1133 NextAddedVariable
= GetNextVariablePtr (AddedVariable
);
1134 NameSize
= NameSizeOfVariable (AddedVariable
);
1135 if (CompareGuid (GetVendorGuidPtr (AddedVariable
), GetVendorGuidPtr (Variable
)) &&
1136 NameSize
== NameSizeOfVariable (Variable
)
1138 Point0
= (VOID
*) GetVariableNamePtr (AddedVariable
);
1139 Point1
= (VOID
*) GetVariableNamePtr (Variable
);
1140 if (CompareMem (Point0
, Point1
, NameSize
) == 0) {
1145 AddedVariable
= NextAddedVariable
;
1149 // Promote VAR_IN_DELETED_TRANSITION to VAR_ADDED.
1151 VariableSize
= (UINTN
) NextVariable
- (UINTN
) Variable
;
1152 CopyMem (CurrPtr
, (UINT8
*) Variable
, VariableSize
);
1153 ((VARIABLE_HEADER
*) CurrPtr
)->State
= VAR_ADDED
;
1154 CurrPtr
+= VariableSize
;
1155 if ((!IsVolatile
) && ((Variable
->Attributes
& EFI_VARIABLE_HARDWARE_ERROR_RECORD
) == EFI_VARIABLE_HARDWARE_ERROR_RECORD
)) {
1156 HwErrVariableTotalSize
+= VariableSize
;
1157 } else if ((!IsVolatile
) && ((Variable
->Attributes
& EFI_VARIABLE_HARDWARE_ERROR_RECORD
) != EFI_VARIABLE_HARDWARE_ERROR_RECORD
)) {
1158 CommonVariableTotalSize
+= VariableSize
;
1159 if (IsUserVariable (Variable
)) {
1160 CommonUserVariableTotalSize
+= VariableSize
;
1166 Variable
= NextVariable
;
1170 // Install the new variable if it is not NULL.
1172 if (NewVariable
!= NULL
) {
1173 if ((UINTN
) (CurrPtr
- ValidBuffer
) + NewVariableSize
> VariableStoreHeader
->Size
) {
1175 // No enough space to store the new variable.
1177 Status
= EFI_OUT_OF_RESOURCES
;
1181 if ((NewVariable
->Attributes
& EFI_VARIABLE_HARDWARE_ERROR_RECORD
) == EFI_VARIABLE_HARDWARE_ERROR_RECORD
) {
1182 HwErrVariableTotalSize
+= NewVariableSize
;
1183 } else if ((NewVariable
->Attributes
& EFI_VARIABLE_HARDWARE_ERROR_RECORD
) != EFI_VARIABLE_HARDWARE_ERROR_RECORD
) {
1184 CommonVariableTotalSize
+= NewVariableSize
;
1185 if (IsUserVariable (NewVariable
)) {
1186 CommonUserVariableTotalSize
+= NewVariableSize
;
1189 if ((HwErrVariableTotalSize
> PcdGet32 (PcdHwErrStorageSize
)) ||
1190 (CommonVariableTotalSize
> mVariableModuleGlobal
->CommonVariableSpace
) ||
1191 (CommonUserVariableTotalSize
> mVariableModuleGlobal
->CommonMaxUserVariableSpace
)) {
1193 // No enough space to store the new variable by NV or NV+HR attribute.
1195 Status
= EFI_OUT_OF_RESOURCES
;
1200 CopyMem (CurrPtr
, (UINT8
*) NewVariable
, NewVariableSize
);
1201 ((VARIABLE_HEADER
*) CurrPtr
)->State
= VAR_ADDED
;
1202 if (UpdatingVariable
!= NULL
) {
1203 UpdatingPtrTrack
->CurrPtr
= (VARIABLE_HEADER
*)((UINTN
)UpdatingPtrTrack
->StartPtr
+ ((UINTN
)CurrPtr
- (UINTN
)GetStartPointer ((VARIABLE_STORE_HEADER
*) ValidBuffer
)));
1204 UpdatingPtrTrack
->InDeletedTransitionPtr
= NULL
;
1206 CurrPtr
+= NewVariableSize
;
1211 // If volatile variable store, just copy valid buffer.
1213 SetMem ((UINT8
*) (UINTN
) VariableBase
, VariableStoreHeader
->Size
, 0xff);
1214 CopyMem ((UINT8
*) (UINTN
) VariableBase
, ValidBuffer
, (UINTN
) (CurrPtr
- ValidBuffer
));
1215 *LastVariableOffset
= (UINTN
) (CurrPtr
- ValidBuffer
);
1216 Status
= EFI_SUCCESS
;
1219 // If non-volatile variable store, perform FTW here.
1221 Status
= FtwVariableSpace (
1223 (VARIABLE_STORE_HEADER
*) ValidBuffer
1225 if (!EFI_ERROR (Status
)) {
1226 *LastVariableOffset
= (UINTN
) (CurrPtr
- ValidBuffer
);
1227 mVariableModuleGlobal
->HwErrVariableTotalSize
= HwErrVariableTotalSize
;
1228 mVariableModuleGlobal
->CommonVariableTotalSize
= CommonVariableTotalSize
;
1229 mVariableModuleGlobal
->CommonUserVariableTotalSize
= CommonUserVariableTotalSize
;
1231 mVariableModuleGlobal
->HwErrVariableTotalSize
= 0;
1232 mVariableModuleGlobal
->CommonVariableTotalSize
= 0;
1233 mVariableModuleGlobal
->CommonUserVariableTotalSize
= 0;
1234 Variable
= GetStartPointer ((VARIABLE_STORE_HEADER
*)(UINTN
)VariableBase
);
1235 while (IsValidVariableHeader (Variable
, GetEndPointer ((VARIABLE_STORE_HEADER
*)(UINTN
)VariableBase
))) {
1236 NextVariable
= GetNextVariablePtr (Variable
);
1237 VariableSize
= (UINTN
) NextVariable
- (UINTN
) Variable
;
1238 if ((Variable
->Attributes
& EFI_VARIABLE_HARDWARE_ERROR_RECORD
) == EFI_VARIABLE_HARDWARE_ERROR_RECORD
) {
1239 mVariableModuleGlobal
->HwErrVariableTotalSize
+= VariableSize
;
1240 } else if ((Variable
->Attributes
& EFI_VARIABLE_HARDWARE_ERROR_RECORD
) != EFI_VARIABLE_HARDWARE_ERROR_RECORD
) {
1241 mVariableModuleGlobal
->CommonVariableTotalSize
+= VariableSize
;
1242 if (IsUserVariable (Variable
)) {
1243 mVariableModuleGlobal
->CommonUserVariableTotalSize
+= VariableSize
;
1247 Variable
= NextVariable
;
1249 *LastVariableOffset
= (UINTN
) Variable
- (UINTN
) VariableBase
;
1255 FreePool (ValidBuffer
);
1258 // For NV variable reclaim, we use mNvVariableCache as the buffer, so copy the data back.
1260 CopyMem (mNvVariableCache
, (UINT8
*)(UINTN
)VariableBase
, VariableStoreHeader
->Size
);
1267 Find the variable in the specified variable store.
1269 @param[in] VariableName Name of the variable to be found
1270 @param[in] VendorGuid Vendor GUID to be found.
1271 @param[in] IgnoreRtCheck Ignore EFI_VARIABLE_RUNTIME_ACCESS attribute
1272 check at runtime when searching variable.
1273 @param[in, out] PtrTrack Variable Track Pointer structure that contains Variable Information.
1275 @retval EFI_SUCCESS Variable found successfully
1276 @retval EFI_NOT_FOUND Variable not found
1280 IN CHAR16
*VariableName
,
1281 IN EFI_GUID
*VendorGuid
,
1282 IN BOOLEAN IgnoreRtCheck
,
1283 IN OUT VARIABLE_POINTER_TRACK
*PtrTrack
1286 VARIABLE_HEADER
*InDeletedVariable
;
1289 PtrTrack
->InDeletedTransitionPtr
= NULL
;
1292 // Find the variable by walk through HOB, volatile and non-volatile variable store.
1294 InDeletedVariable
= NULL
;
1296 for ( PtrTrack
->CurrPtr
= PtrTrack
->StartPtr
1297 ; IsValidVariableHeader (PtrTrack
->CurrPtr
, PtrTrack
->EndPtr
)
1298 ; PtrTrack
->CurrPtr
= GetNextVariablePtr (PtrTrack
->CurrPtr
)
1300 if (PtrTrack
->CurrPtr
->State
== VAR_ADDED
||
1301 PtrTrack
->CurrPtr
->State
== (VAR_IN_DELETED_TRANSITION
& VAR_ADDED
)
1303 if (IgnoreRtCheck
|| !AtRuntime () || ((PtrTrack
->CurrPtr
->Attributes
& EFI_VARIABLE_RUNTIME_ACCESS
) != 0)) {
1304 if (VariableName
[0] == 0) {
1305 if (PtrTrack
->CurrPtr
->State
== (VAR_IN_DELETED_TRANSITION
& VAR_ADDED
)) {
1306 InDeletedVariable
= PtrTrack
->CurrPtr
;
1308 PtrTrack
->InDeletedTransitionPtr
= InDeletedVariable
;
1312 if (CompareGuid (VendorGuid
, GetVendorGuidPtr (PtrTrack
->CurrPtr
))) {
1313 Point
= (VOID
*) GetVariableNamePtr (PtrTrack
->CurrPtr
);
1315 ASSERT (NameSizeOfVariable (PtrTrack
->CurrPtr
) != 0);
1316 if (CompareMem (VariableName
, Point
, NameSizeOfVariable (PtrTrack
->CurrPtr
)) == 0) {
1317 if (PtrTrack
->CurrPtr
->State
== (VAR_IN_DELETED_TRANSITION
& VAR_ADDED
)) {
1318 InDeletedVariable
= PtrTrack
->CurrPtr
;
1320 PtrTrack
->InDeletedTransitionPtr
= InDeletedVariable
;
1330 PtrTrack
->CurrPtr
= InDeletedVariable
;
1331 return (PtrTrack
->CurrPtr
== NULL
) ? EFI_NOT_FOUND
: EFI_SUCCESS
;
1336 Finds variable in storage blocks of volatile and non-volatile storage areas.
1338 This code finds variable in storage blocks of volatile and non-volatile storage areas.
1339 If VariableName is an empty string, then we just return the first
1340 qualified variable without comparing VariableName and VendorGuid.
1341 If IgnoreRtCheck is TRUE, then we ignore the EFI_VARIABLE_RUNTIME_ACCESS attribute check
1342 at runtime when searching existing variable, only VariableName and VendorGuid are compared.
1343 Otherwise, variables without EFI_VARIABLE_RUNTIME_ACCESS are not visible at runtime.
1345 @param[in] VariableName Name of the variable to be found.
1346 @param[in] VendorGuid Vendor GUID to be found.
1347 @param[out] PtrTrack VARIABLE_POINTER_TRACK structure for output,
1348 including the range searched and the target position.
1349 @param[in] Global Pointer to VARIABLE_GLOBAL structure, including
1350 base of volatile variable storage area, base of
1351 NV variable storage area, and a lock.
1352 @param[in] IgnoreRtCheck Ignore EFI_VARIABLE_RUNTIME_ACCESS attribute
1353 check at runtime when searching variable.
1355 @retval EFI_INVALID_PARAMETER If VariableName is not an empty string, while
1357 @retval EFI_SUCCESS Variable successfully found.
1358 @retval EFI_NOT_FOUND Variable not found
1363 IN CHAR16
*VariableName
,
1364 IN EFI_GUID
*VendorGuid
,
1365 OUT VARIABLE_POINTER_TRACK
*PtrTrack
,
1366 IN VARIABLE_GLOBAL
*Global
,
1367 IN BOOLEAN IgnoreRtCheck
1371 VARIABLE_STORE_HEADER
*VariableStoreHeader
[VariableStoreTypeMax
];
1372 VARIABLE_STORE_TYPE Type
;
1374 if (VariableName
[0] != 0 && VendorGuid
== NULL
) {
1375 return EFI_INVALID_PARAMETER
;
1379 // 0: Volatile, 1: HOB, 2: Non-Volatile.
1380 // The index and attributes mapping must be kept in this order as RuntimeServiceGetNextVariableName
1381 // make use of this mapping to implement search algorithm.
1383 VariableStoreHeader
[VariableStoreTypeVolatile
] = (VARIABLE_STORE_HEADER
*) (UINTN
) Global
->VolatileVariableBase
;
1384 VariableStoreHeader
[VariableStoreTypeHob
] = (VARIABLE_STORE_HEADER
*) (UINTN
) Global
->HobVariableBase
;
1385 VariableStoreHeader
[VariableStoreTypeNv
] = mNvVariableCache
;
1388 // Find the variable by walk through HOB, volatile and non-volatile variable store.
1390 for (Type
= (VARIABLE_STORE_TYPE
) 0; Type
< VariableStoreTypeMax
; Type
++) {
1391 if (VariableStoreHeader
[Type
] == NULL
) {
1395 PtrTrack
->StartPtr
= GetStartPointer (VariableStoreHeader
[Type
]);
1396 PtrTrack
->EndPtr
= GetEndPointer (VariableStoreHeader
[Type
]);
1397 PtrTrack
->Volatile
= (BOOLEAN
) (Type
== VariableStoreTypeVolatile
);
1399 Status
= FindVariableEx (VariableName
, VendorGuid
, IgnoreRtCheck
, PtrTrack
);
1400 if (!EFI_ERROR (Status
)) {
1404 return EFI_NOT_FOUND
;
1408 Get index from supported language codes according to language string.
1410 This code is used to get corresponding index in supported language codes. It can handle
1411 RFC4646 and ISO639 language tags.
1412 In ISO639 language tags, take 3-characters as a delimitation to find matched string and calculate the index.
1413 In RFC4646 language tags, take semicolon as a delimitation to find matched string and calculate the index.
1416 SupportedLang = "engfraengfra"
1418 Iso639Language = TRUE
1419 The return value is "0".
1421 SupportedLang = "en;fr;en-US;fr-FR"
1423 Iso639Language = FALSE
1424 The return value is "3".
1426 @param SupportedLang Platform supported language codes.
1427 @param Lang Configured language.
1428 @param Iso639Language A bool value to signify if the handler is operated on ISO639 or RFC4646.
1430 @retval The index of language in the language codes.
1434 GetIndexFromSupportedLangCodes(
1435 IN CHAR8
*SupportedLang
,
1437 IN BOOLEAN Iso639Language
1441 UINTN CompareLength
;
1442 UINTN LanguageLength
;
1444 if (Iso639Language
) {
1445 CompareLength
= ISO_639_2_ENTRY_SIZE
;
1446 for (Index
= 0; Index
< AsciiStrLen (SupportedLang
); Index
+= CompareLength
) {
1447 if (AsciiStrnCmp (Lang
, SupportedLang
+ Index
, CompareLength
) == 0) {
1449 // Successfully find the index of Lang string in SupportedLang string.
1451 Index
= Index
/ CompareLength
;
1459 // Compare RFC4646 language code
1462 for (LanguageLength
= 0; Lang
[LanguageLength
] != '\0'; LanguageLength
++);
1464 for (Index
= 0; *SupportedLang
!= '\0'; Index
++, SupportedLang
+= CompareLength
) {
1466 // Skip ';' characters in SupportedLang
1468 for (; *SupportedLang
!= '\0' && *SupportedLang
== ';'; SupportedLang
++);
1470 // Determine the length of the next language code in SupportedLang
1472 for (CompareLength
= 0; SupportedLang
[CompareLength
] != '\0' && SupportedLang
[CompareLength
] != ';'; CompareLength
++);
1474 if ((CompareLength
== LanguageLength
) &&
1475 (AsciiStrnCmp (Lang
, SupportedLang
, CompareLength
) == 0)) {
1477 // Successfully find the index of Lang string in SupportedLang string.
1488 Get language string from supported language codes according to index.
1490 This code is used to get corresponding language strings in supported language codes. It can handle
1491 RFC4646 and ISO639 language tags.
1492 In ISO639 language tags, take 3-characters as a delimitation. Find language string according to the index.
1493 In RFC4646 language tags, take semicolon as a delimitation. Find language string according to the index.
1496 SupportedLang = "engfraengfra"
1498 Iso639Language = TRUE
1499 The return value is "fra".
1501 SupportedLang = "en;fr;en-US;fr-FR"
1503 Iso639Language = FALSE
1504 The return value is "fr".
1506 @param SupportedLang Platform supported language codes.
1507 @param Index The index in supported language codes.
1508 @param Iso639Language A bool value to signify if the handler is operated on ISO639 or RFC4646.
1510 @retval The language string in the language codes.
1514 GetLangFromSupportedLangCodes (
1515 IN CHAR8
*SupportedLang
,
1517 IN BOOLEAN Iso639Language
1521 UINTN CompareLength
;
1525 Supported
= SupportedLang
;
1526 if (Iso639Language
) {
1528 // According to the index of Lang string in SupportedLang string to get the language.
1529 // This code will be invoked in RUNTIME, therefore there is not a memory allocate/free operation.
1530 // In driver entry, it pre-allocates a runtime attribute memory to accommodate this string.
1532 CompareLength
= ISO_639_2_ENTRY_SIZE
;
1533 mVariableModuleGlobal
->Lang
[CompareLength
] = '\0';
1534 return CopyMem (mVariableModuleGlobal
->Lang
, SupportedLang
+ Index
* CompareLength
, CompareLength
);
1539 // Take semicolon as delimitation, sequentially traverse supported language codes.
1541 for (CompareLength
= 0; *Supported
!= ';' && *Supported
!= '\0'; CompareLength
++) {
1544 if ((*Supported
== '\0') && (SubIndex
!= Index
)) {
1546 // Have completed the traverse, but not find corrsponding string.
1547 // This case is not allowed to happen.
1552 if (SubIndex
== Index
) {
1554 // According to the index of Lang string in SupportedLang string to get the language.
1555 // As this code will be invoked in RUNTIME, therefore there is not memory allocate/free operation.
1556 // In driver entry, it pre-allocates a runtime attribute memory to accommodate this string.
1558 mVariableModuleGlobal
->PlatformLang
[CompareLength
] = '\0';
1559 return CopyMem (mVariableModuleGlobal
->PlatformLang
, Supported
- CompareLength
, CompareLength
);
1564 // Skip ';' characters in Supported
1566 for (; *Supported
!= '\0' && *Supported
== ';'; Supported
++);
1572 Returns a pointer to an allocated buffer that contains the best matching language
1573 from a set of supported languages.
1575 This function supports both ISO 639-2 and RFC 4646 language codes, but language
1576 code types may not be mixed in a single call to this function. This function
1577 supports a variable argument list that allows the caller to pass in a prioritized
1578 list of language codes to test against all the language codes in SupportedLanguages.
1580 If SupportedLanguages is NULL, then ASSERT().
1582 @param[in] SupportedLanguages A pointer to a Null-terminated ASCII string that
1583 contains a set of language codes in the format
1584 specified by Iso639Language.
1585 @param[in] Iso639Language If TRUE, then all language codes are assumed to be
1586 in ISO 639-2 format. If FALSE, then all language
1587 codes are assumed to be in RFC 4646 language format
1588 @param[in] ... A variable argument list that contains pointers to
1589 Null-terminated ASCII strings that contain one or more
1590 language codes in the format specified by Iso639Language.
1591 The first language code from each of these language
1592 code lists is used to determine if it is an exact or
1593 close match to any of the language codes in
1594 SupportedLanguages. Close matches only apply to RFC 4646
1595 language codes, and the matching algorithm from RFC 4647
1596 is used to determine if a close match is present. If
1597 an exact or close match is found, then the matching
1598 language code from SupportedLanguages is returned. If
1599 no matches are found, then the next variable argument
1600 parameter is evaluated. The variable argument list
1601 is terminated by a NULL.
1603 @retval NULL The best matching language could not be found in SupportedLanguages.
1604 @retval NULL There are not enough resources available to return the best matching
1606 @retval Other A pointer to a Null-terminated ASCII string that is the best matching
1607 language in SupportedLanguages.
1612 VariableGetBestLanguage (
1613 IN CONST CHAR8
*SupportedLanguages
,
1614 IN BOOLEAN Iso639Language
,
1620 UINTN CompareLength
;
1621 UINTN LanguageLength
;
1622 CONST CHAR8
*Supported
;
1625 if (SupportedLanguages
== NULL
) {
1629 VA_START (Args
, Iso639Language
);
1630 while ((Language
= VA_ARG (Args
, CHAR8
*)) != NULL
) {
1632 // Default to ISO 639-2 mode
1635 LanguageLength
= MIN (3, AsciiStrLen (Language
));
1638 // If in RFC 4646 mode, then determine the length of the first RFC 4646 language code in Language
1640 if (!Iso639Language
) {
1641 for (LanguageLength
= 0; Language
[LanguageLength
] != 0 && Language
[LanguageLength
] != ';'; LanguageLength
++);
1645 // Trim back the length of Language used until it is empty
1647 while (LanguageLength
> 0) {
1649 // Loop through all language codes in SupportedLanguages
1651 for (Supported
= SupportedLanguages
; *Supported
!= '\0'; Supported
+= CompareLength
) {
1653 // In RFC 4646 mode, then Loop through all language codes in SupportedLanguages
1655 if (!Iso639Language
) {
1657 // Skip ';' characters in Supported
1659 for (; *Supported
!= '\0' && *Supported
== ';'; Supported
++);
1661 // Determine the length of the next language code in Supported
1663 for (CompareLength
= 0; Supported
[CompareLength
] != 0 && Supported
[CompareLength
] != ';'; CompareLength
++);
1665 // If Language is longer than the Supported, then skip to the next language
1667 if (LanguageLength
> CompareLength
) {
1672 // See if the first LanguageLength characters in Supported match Language
1674 if (AsciiStrnCmp (Supported
, Language
, LanguageLength
) == 0) {
1677 Buffer
= Iso639Language
? mVariableModuleGlobal
->Lang
: mVariableModuleGlobal
->PlatformLang
;
1678 Buffer
[CompareLength
] = '\0';
1679 return CopyMem (Buffer
, Supported
, CompareLength
);
1683 if (Iso639Language
) {
1685 // If ISO 639 mode, then each language can only be tested once
1690 // If RFC 4646 mode, then trim Language from the right to the next '-' character
1692 for (LanguageLength
--; LanguageLength
> 0 && Language
[LanguageLength
] != '-'; LanguageLength
--);
1699 // No matches were found
1705 This function is to check if the remaining variable space is enough to set
1706 all Variables from argument list successfully. The purpose of the check
1707 is to keep the consistency of the Variables to be in variable storage.
1709 Note: Variables are assumed to be in same storage.
1710 The set sequence of Variables will be same with the sequence of VariableEntry from argument list,
1711 so follow the argument sequence to check the Variables.
1713 @param[in] Attributes Variable attributes for Variable entries.
1714 @param[in] Marker VA_LIST style variable argument list.
1715 The variable argument list with type VARIABLE_ENTRY_CONSISTENCY *.
1716 A NULL terminates the list. The VariableSize of
1717 VARIABLE_ENTRY_CONSISTENCY is the variable data size as input.
1718 It will be changed to variable total size as output.
1720 @retval TRUE Have enough variable space to set the Variables successfully.
1721 @retval FALSE No enough variable space to set the Variables successfully.
1726 CheckRemainingSpaceForConsistencyInternal (
1727 IN UINT32 Attributes
,
1733 VARIABLE_ENTRY_CONSISTENCY
*VariableEntry
;
1734 UINT64 MaximumVariableStorageSize
;
1735 UINT64 RemainingVariableStorageSize
;
1736 UINT64 MaximumVariableSize
;
1737 UINTN TotalNeededSize
;
1738 UINTN OriginalVarSize
;
1739 VARIABLE_STORE_HEADER
*VariableStoreHeader
;
1740 VARIABLE_POINTER_TRACK VariablePtrTrack
;
1741 VARIABLE_HEADER
*NextVariable
;
1746 // Non-Volatile related.
1748 VariableStoreHeader
= mNvVariableCache
;
1750 Status
= VariableServiceQueryVariableInfoInternal (
1752 &MaximumVariableStorageSize
,
1753 &RemainingVariableStorageSize
,
1754 &MaximumVariableSize
1756 ASSERT_EFI_ERROR (Status
);
1758 TotalNeededSize
= 0;
1759 VA_COPY (Args
, Marker
);
1760 VariableEntry
= VA_ARG (Args
, VARIABLE_ENTRY_CONSISTENCY
*);
1761 while (VariableEntry
!= NULL
) {
1763 // Calculate variable total size.
1765 VarNameSize
= StrSize (VariableEntry
->Name
);
1766 VarNameSize
+= GET_PAD_SIZE (VarNameSize
);
1767 VarDataSize
= VariableEntry
->VariableSize
;
1768 VarDataSize
+= GET_PAD_SIZE (VarDataSize
);
1769 VariableEntry
->VariableSize
= HEADER_ALIGN (GetVariableHeaderSize () + VarNameSize
+ VarDataSize
);
1771 TotalNeededSize
+= VariableEntry
->VariableSize
;
1772 VariableEntry
= VA_ARG (Args
, VARIABLE_ENTRY_CONSISTENCY
*);
1775 if (RemainingVariableStorageSize
>= TotalNeededSize
) {
1777 // Already have enough space.
1780 } else if (AtRuntime ()) {
1782 // At runtime, no reclaim.
1783 // The original variable space of Variables can't be reused.
1788 VA_COPY (Args
, Marker
);
1789 VariableEntry
= VA_ARG (Args
, VARIABLE_ENTRY_CONSISTENCY
*);
1790 while (VariableEntry
!= NULL
) {
1792 // Check if Variable[Index] has been present and get its size.
1794 OriginalVarSize
= 0;
1795 VariablePtrTrack
.StartPtr
= GetStartPointer (VariableStoreHeader
);
1796 VariablePtrTrack
.EndPtr
= GetEndPointer (VariableStoreHeader
);
1797 Status
= FindVariableEx (
1798 VariableEntry
->Name
,
1799 VariableEntry
->Guid
,
1803 if (!EFI_ERROR (Status
)) {
1805 // Get size of Variable[Index].
1807 NextVariable
= GetNextVariablePtr (VariablePtrTrack
.CurrPtr
);
1808 OriginalVarSize
= (UINTN
) NextVariable
- (UINTN
) VariablePtrTrack
.CurrPtr
;
1810 // Add the original size of Variable[Index] to remaining variable storage size.
1812 RemainingVariableStorageSize
+= OriginalVarSize
;
1814 if (VariableEntry
->VariableSize
> RemainingVariableStorageSize
) {
1816 // No enough space for Variable[Index].
1821 // Sub the (new) size of Variable[Index] from remaining variable storage size.
1823 RemainingVariableStorageSize
-= VariableEntry
->VariableSize
;
1824 VariableEntry
= VA_ARG (Args
, VARIABLE_ENTRY_CONSISTENCY
*);
1831 This function is to check if the remaining variable space is enough to set
1832 all Variables from argument list successfully. The purpose of the check
1833 is to keep the consistency of the Variables to be in variable storage.
1835 Note: Variables are assumed to be in same storage.
1836 The set sequence of Variables will be same with the sequence of VariableEntry from argument list,
1837 so follow the argument sequence to check the Variables.
1839 @param[in] Attributes Variable attributes for Variable entries.
1840 @param ... The variable argument list with type VARIABLE_ENTRY_CONSISTENCY *.
1841 A NULL terminates the list. The VariableSize of
1842 VARIABLE_ENTRY_CONSISTENCY is the variable data size as input.
1843 It will be changed to variable total size as output.
1845 @retval TRUE Have enough variable space to set the Variables successfully.
1846 @retval FALSE No enough variable space to set the Variables successfully.
1851 CheckRemainingSpaceForConsistency (
1852 IN UINT32 Attributes
,
1859 VA_START (Marker
, Attributes
);
1861 Return
= CheckRemainingSpaceForConsistencyInternal (Attributes
, Marker
);
1869 Hook the operations in PlatformLangCodes, LangCodes, PlatformLang and Lang.
1871 When setting Lang/LangCodes, simultaneously update PlatformLang/PlatformLangCodes.
1873 According to UEFI spec, PlatformLangCodes/LangCodes are only set once in firmware initialization,
1874 and are read-only. Therefore, in variable driver, only store the original value for other use.
1876 @param[in] VariableName Name of variable.
1878 @param[in] Data Variable data.
1880 @param[in] DataSize Size of data. 0 means delete.
1882 @retval EFI_SUCCESS The update operation is successful or ignored.
1883 @retval EFI_WRITE_PROTECTED Update PlatformLangCodes/LangCodes at runtime.
1884 @retval EFI_OUT_OF_RESOURCES No enough variable space to do the update operation.
1885 @retval Others Other errors happened during the update operation.
1889 AutoUpdateLangVariable (
1890 IN CHAR16
*VariableName
,
1896 CHAR8
*BestPlatformLang
;
1900 VARIABLE_POINTER_TRACK Variable
;
1901 BOOLEAN SetLanguageCodes
;
1902 VARIABLE_ENTRY_CONSISTENCY VariableEntry
[2];
1905 // Don't do updates for delete operation
1907 if (DataSize
== 0) {
1911 SetLanguageCodes
= FALSE
;
1913 if (StrCmp (VariableName
, EFI_PLATFORM_LANG_CODES_VARIABLE_NAME
) == 0) {
1915 // PlatformLangCodes is a volatile variable, so it can not be updated at runtime.
1918 return EFI_WRITE_PROTECTED
;
1921 SetLanguageCodes
= TRUE
;
1924 // According to UEFI spec, PlatformLangCodes is only set once in firmware initialization, and is read-only
1925 // Therefore, in variable driver, only store the original value for other use.
1927 if (mVariableModuleGlobal
->PlatformLangCodes
!= NULL
) {
1928 FreePool (mVariableModuleGlobal
->PlatformLangCodes
);
1930 mVariableModuleGlobal
->PlatformLangCodes
= AllocateRuntimeCopyPool (DataSize
, Data
);
1931 ASSERT (mVariableModuleGlobal
->PlatformLangCodes
!= NULL
);
1934 // PlatformLang holds a single language from PlatformLangCodes,
1935 // so the size of PlatformLangCodes is enough for the PlatformLang.
1937 if (mVariableModuleGlobal
->PlatformLang
!= NULL
) {
1938 FreePool (mVariableModuleGlobal
->PlatformLang
);
1940 mVariableModuleGlobal
->PlatformLang
= AllocateRuntimePool (DataSize
);
1941 ASSERT (mVariableModuleGlobal
->PlatformLang
!= NULL
);
1943 } else if (StrCmp (VariableName
, EFI_LANG_CODES_VARIABLE_NAME
) == 0) {
1945 // LangCodes is a volatile variable, so it can not be updated at runtime.
1948 return EFI_WRITE_PROTECTED
;
1951 SetLanguageCodes
= TRUE
;
1954 // According to UEFI spec, LangCodes is only set once in firmware initialization, and is read-only
1955 // Therefore, in variable driver, only store the original value for other use.
1957 if (mVariableModuleGlobal
->LangCodes
!= NULL
) {
1958 FreePool (mVariableModuleGlobal
->LangCodes
);
1960 mVariableModuleGlobal
->LangCodes
= AllocateRuntimeCopyPool (DataSize
, Data
);
1961 ASSERT (mVariableModuleGlobal
->LangCodes
!= NULL
);
1964 if (SetLanguageCodes
1965 && (mVariableModuleGlobal
->PlatformLangCodes
!= NULL
)
1966 && (mVariableModuleGlobal
->LangCodes
!= NULL
)) {
1968 // Update Lang if PlatformLang is already set
1969 // Update PlatformLang if Lang is already set
1971 Status
= FindVariable (EFI_PLATFORM_LANG_VARIABLE_NAME
, &gEfiGlobalVariableGuid
, &Variable
, &mVariableModuleGlobal
->VariableGlobal
, FALSE
);
1972 if (!EFI_ERROR (Status
)) {
1976 VariableName
= EFI_PLATFORM_LANG_VARIABLE_NAME
;
1977 Data
= GetVariableDataPtr (Variable
.CurrPtr
);
1978 DataSize
= DataSizeOfVariable (Variable
.CurrPtr
);
1980 Status
= FindVariable (EFI_LANG_VARIABLE_NAME
, &gEfiGlobalVariableGuid
, &Variable
, &mVariableModuleGlobal
->VariableGlobal
, FALSE
);
1981 if (!EFI_ERROR (Status
)) {
1983 // Update PlatformLang
1985 VariableName
= EFI_LANG_VARIABLE_NAME
;
1986 Data
= GetVariableDataPtr (Variable
.CurrPtr
);
1987 DataSize
= DataSizeOfVariable (Variable
.CurrPtr
);
1990 // Neither PlatformLang nor Lang is set, directly return
1997 Status
= EFI_SUCCESS
;
2000 // According to UEFI spec, "Lang" and "PlatformLang" is NV|BS|RT attributions.
2002 Attributes
= EFI_VARIABLE_NON_VOLATILE
| EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_RUNTIME_ACCESS
;
2004 if (StrCmp (VariableName
, EFI_PLATFORM_LANG_VARIABLE_NAME
) == 0) {
2006 // Update Lang when PlatformLangCodes/LangCodes were set.
2008 if ((mVariableModuleGlobal
->PlatformLangCodes
!= NULL
) && (mVariableModuleGlobal
->LangCodes
!= NULL
)) {
2010 // When setting PlatformLang, firstly get most matched language string from supported language codes.
2012 BestPlatformLang
= VariableGetBestLanguage (mVariableModuleGlobal
->PlatformLangCodes
, FALSE
, Data
, NULL
);
2013 if (BestPlatformLang
!= NULL
) {
2015 // Get the corresponding index in language codes.
2017 Index
= GetIndexFromSupportedLangCodes (mVariableModuleGlobal
->PlatformLangCodes
, BestPlatformLang
, FALSE
);
2020 // Get the corresponding ISO639 language tag according to RFC4646 language tag.
2022 BestLang
= GetLangFromSupportedLangCodes (mVariableModuleGlobal
->LangCodes
, Index
, TRUE
);
2025 // Check the variable space for both Lang and PlatformLang variable.
2027 VariableEntry
[0].VariableSize
= ISO_639_2_ENTRY_SIZE
+ 1;
2028 VariableEntry
[0].Guid
= &gEfiGlobalVariableGuid
;
2029 VariableEntry
[0].Name
= EFI_LANG_VARIABLE_NAME
;
2031 VariableEntry
[1].VariableSize
= AsciiStrSize (BestPlatformLang
);
2032 VariableEntry
[1].Guid
= &gEfiGlobalVariableGuid
;
2033 VariableEntry
[1].Name
= EFI_PLATFORM_LANG_VARIABLE_NAME
;
2034 if (!CheckRemainingSpaceForConsistency (VARIABLE_ATTRIBUTE_NV_BS_RT
, &VariableEntry
[0], &VariableEntry
[1], NULL
)) {
2036 // No enough variable space to set both Lang and PlatformLang successfully.
2038 Status
= EFI_OUT_OF_RESOURCES
;
2041 // Successfully convert PlatformLang to Lang, and set the BestLang value into Lang variable simultaneously.
2043 FindVariable (EFI_LANG_VARIABLE_NAME
, &gEfiGlobalVariableGuid
, &Variable
, &mVariableModuleGlobal
->VariableGlobal
, FALSE
);
2045 Status
= UpdateVariable (EFI_LANG_VARIABLE_NAME
, &gEfiGlobalVariableGuid
, BestLang
,
2046 ISO_639_2_ENTRY_SIZE
+ 1, Attributes
, 0, 0, &Variable
, NULL
);
2049 DEBUG ((EFI_D_INFO
, "Variable Driver Auto Update PlatformLang, PlatformLang:%a, Lang:%a Status: %r\n", BestPlatformLang
, BestLang
, Status
));
2053 } else if (StrCmp (VariableName
, EFI_LANG_VARIABLE_NAME
) == 0) {
2055 // Update PlatformLang when PlatformLangCodes/LangCodes were set.
2057 if ((mVariableModuleGlobal
->PlatformLangCodes
!= NULL
) && (mVariableModuleGlobal
->LangCodes
!= NULL
)) {
2059 // When setting Lang, firstly get most matched language string from supported language codes.
2061 BestLang
= VariableGetBestLanguage (mVariableModuleGlobal
->LangCodes
, TRUE
, Data
, NULL
);
2062 if (BestLang
!= NULL
) {
2064 // Get the corresponding index in language codes.
2066 Index
= GetIndexFromSupportedLangCodes (mVariableModuleGlobal
->LangCodes
, BestLang
, TRUE
);
2069 // Get the corresponding RFC4646 language tag according to ISO639 language tag.
2071 BestPlatformLang
= GetLangFromSupportedLangCodes (mVariableModuleGlobal
->PlatformLangCodes
, Index
, FALSE
);
2074 // Check the variable space for both PlatformLang and Lang variable.
2076 VariableEntry
[0].VariableSize
= AsciiStrSize (BestPlatformLang
);
2077 VariableEntry
[0].Guid
= &gEfiGlobalVariableGuid
;
2078 VariableEntry
[0].Name
= EFI_PLATFORM_LANG_VARIABLE_NAME
;
2080 VariableEntry
[1].VariableSize
= ISO_639_2_ENTRY_SIZE
+ 1;
2081 VariableEntry
[1].Guid
= &gEfiGlobalVariableGuid
;
2082 VariableEntry
[1].Name
= EFI_LANG_VARIABLE_NAME
;
2083 if (!CheckRemainingSpaceForConsistency (VARIABLE_ATTRIBUTE_NV_BS_RT
, &VariableEntry
[0], &VariableEntry
[1], NULL
)) {
2085 // No enough variable space to set both PlatformLang and Lang successfully.
2087 Status
= EFI_OUT_OF_RESOURCES
;
2090 // Successfully convert Lang to PlatformLang, and set the BestPlatformLang value into PlatformLang variable simultaneously.
2092 FindVariable (EFI_PLATFORM_LANG_VARIABLE_NAME
, &gEfiGlobalVariableGuid
, &Variable
, &mVariableModuleGlobal
->VariableGlobal
, FALSE
);
2094 Status
= UpdateVariable (EFI_PLATFORM_LANG_VARIABLE_NAME
, &gEfiGlobalVariableGuid
, BestPlatformLang
,
2095 AsciiStrSize (BestPlatformLang
), Attributes
, 0, 0, &Variable
, NULL
);
2098 DEBUG ((EFI_D_INFO
, "Variable Driver Auto Update Lang, Lang:%a, PlatformLang:%a Status: %r\n", BestLang
, BestPlatformLang
, Status
));
2103 if (SetLanguageCodes
) {
2105 // Continue to set PlatformLangCodes or LangCodes.
2114 Compare two EFI_TIME data.
2117 @param FirstTime A pointer to the first EFI_TIME data.
2118 @param SecondTime A pointer to the second EFI_TIME data.
2120 @retval TRUE The FirstTime is not later than the SecondTime.
2121 @retval FALSE The FirstTime is later than the SecondTime.
2125 VariableCompareTimeStampInternal (
2126 IN EFI_TIME
*FirstTime
,
2127 IN EFI_TIME
*SecondTime
2130 if (FirstTime
->Year
!= SecondTime
->Year
) {
2131 return (BOOLEAN
) (FirstTime
->Year
< SecondTime
->Year
);
2132 } else if (FirstTime
->Month
!= SecondTime
->Month
) {
2133 return (BOOLEAN
) (FirstTime
->Month
< SecondTime
->Month
);
2134 } else if (FirstTime
->Day
!= SecondTime
->Day
) {
2135 return (BOOLEAN
) (FirstTime
->Day
< SecondTime
->Day
);
2136 } else if (FirstTime
->Hour
!= SecondTime
->Hour
) {
2137 return (BOOLEAN
) (FirstTime
->Hour
< SecondTime
->Hour
);
2138 } else if (FirstTime
->Minute
!= SecondTime
->Minute
) {
2139 return (BOOLEAN
) (FirstTime
->Minute
< SecondTime
->Minute
);
2142 return (BOOLEAN
) (FirstTime
->Second
<= SecondTime
->Second
);
2146 Update the variable region with Variable information. If EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS is set,
2147 index of associated public key is needed.
2149 @param[in] VariableName Name of variable.
2150 @param[in] VendorGuid Guid of variable.
2151 @param[in] Data Variable data.
2152 @param[in] DataSize Size of data. 0 means delete.
2153 @param[in] Attributes Attributes of the variable.
2154 @param[in] KeyIndex Index of associated public key.
2155 @param[in] MonotonicCount Value of associated monotonic count.
2156 @param[in, out] CacheVariable The variable information which is used to keep track of variable usage.
2157 @param[in] TimeStamp Value of associated TimeStamp.
2159 @retval EFI_SUCCESS The update operation is success.
2160 @retval EFI_OUT_OF_RESOURCES Variable region is full, can not write other data into this region.
2165 IN CHAR16
*VariableName
,
2166 IN EFI_GUID
*VendorGuid
,
2169 IN UINT32 Attributes OPTIONAL
,
2170 IN UINT32 KeyIndex OPTIONAL
,
2171 IN UINT64 MonotonicCount OPTIONAL
,
2172 IN OUT VARIABLE_POINTER_TRACK
*CacheVariable
,
2173 IN EFI_TIME
*TimeStamp OPTIONAL
2177 VARIABLE_HEADER
*NextVariable
;
2180 UINTN VarNameOffset
;
2181 UINTN VarDataOffset
;
2185 EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*Fvb
;
2187 VARIABLE_POINTER_TRACK
*Variable
;
2188 VARIABLE_POINTER_TRACK NvVariable
;
2189 VARIABLE_STORE_HEADER
*VariableStoreHeader
;
2191 UINT8
*BufferForMerge
;
2192 UINTN MergedBufSize
;
2195 BOOLEAN IsCommonVariable
;
2196 BOOLEAN IsCommonUserVariable
;
2197 AUTHENTICATED_VARIABLE_HEADER
*AuthVariable
;
2199 if (mVariableModuleGlobal
->FvbInstance
== NULL
) {
2201 // The FVB protocol is not ready, so the EFI_VARIABLE_WRITE_ARCH_PROTOCOL is not installed.
2203 if ((Attributes
& EFI_VARIABLE_NON_VOLATILE
) != 0) {
2205 // Trying to update NV variable prior to the installation of EFI_VARIABLE_WRITE_ARCH_PROTOCOL
2207 DEBUG ((EFI_D_ERROR
, "Update NV variable before EFI_VARIABLE_WRITE_ARCH_PROTOCOL ready - %r\n", EFI_NOT_AVAILABLE_YET
));
2208 return EFI_NOT_AVAILABLE_YET
;
2209 } else if ((Attributes
& VARIABLE_ATTRIBUTE_AT_AW
) != 0) {
2211 // Trying to update volatile authenticated variable prior to the installation of EFI_VARIABLE_WRITE_ARCH_PROTOCOL
2212 // The authenticated variable perhaps is not initialized, just return here.
2214 DEBUG ((EFI_D_ERROR
, "Update AUTH variable before EFI_VARIABLE_WRITE_ARCH_PROTOCOL ready - %r\n", EFI_NOT_AVAILABLE_YET
));
2215 return EFI_NOT_AVAILABLE_YET
;
2220 // Check if CacheVariable points to the variable in variable HOB.
2221 // If yes, let CacheVariable points to the variable in NV variable cache.
2223 if ((CacheVariable
->CurrPtr
!= NULL
) &&
2224 (mVariableModuleGlobal
->VariableGlobal
.HobVariableBase
!= 0) &&
2225 (CacheVariable
->StartPtr
== GetStartPointer ((VARIABLE_STORE_HEADER
*) (UINTN
) mVariableModuleGlobal
->VariableGlobal
.HobVariableBase
))
2227 CacheVariable
->StartPtr
= GetStartPointer (mNvVariableCache
);
2228 CacheVariable
->EndPtr
= GetEndPointer (mNvVariableCache
);
2229 CacheVariable
->Volatile
= FALSE
;
2230 Status
= FindVariableEx (VariableName
, VendorGuid
, FALSE
, CacheVariable
);
2231 if (CacheVariable
->CurrPtr
== NULL
|| EFI_ERROR (Status
)) {
2233 // There is no matched variable in NV variable cache.
2235 if ((((Attributes
& EFI_VARIABLE_APPEND_WRITE
) == 0) && (DataSize
== 0)) || (Attributes
== 0)) {
2237 // It is to delete variable,
2238 // go to delete this variable in variable HOB and
2239 // try to flush other variables from HOB to flash.
2241 UpdateVariableInfo (VariableName
, VendorGuid
, FALSE
, FALSE
, FALSE
, TRUE
, FALSE
);
2242 FlushHobVariableToFlash (VariableName
, VendorGuid
);
2248 if ((CacheVariable
->CurrPtr
== NULL
) || CacheVariable
->Volatile
) {
2249 Variable
= CacheVariable
;
2252 // Update/Delete existing NV variable.
2253 // CacheVariable points to the variable in the memory copy of Flash area
2254 // Now let Variable points to the same variable in Flash area.
2256 VariableStoreHeader
= (VARIABLE_STORE_HEADER
*) ((UINTN
) mVariableModuleGlobal
->VariableGlobal
.NonVolatileVariableBase
);
2257 Variable
= &NvVariable
;
2258 Variable
->StartPtr
= GetStartPointer (VariableStoreHeader
);
2259 Variable
->EndPtr
= (VARIABLE_HEADER
*)((UINTN
)Variable
->StartPtr
+ ((UINTN
)CacheVariable
->EndPtr
- (UINTN
)CacheVariable
->StartPtr
));
2261 Variable
->CurrPtr
= (VARIABLE_HEADER
*)((UINTN
)Variable
->StartPtr
+ ((UINTN
)CacheVariable
->CurrPtr
- (UINTN
)CacheVariable
->StartPtr
));
2262 if (CacheVariable
->InDeletedTransitionPtr
!= NULL
) {
2263 Variable
->InDeletedTransitionPtr
= (VARIABLE_HEADER
*)((UINTN
)Variable
->StartPtr
+ ((UINTN
)CacheVariable
->InDeletedTransitionPtr
- (UINTN
)CacheVariable
->StartPtr
));
2265 Variable
->InDeletedTransitionPtr
= NULL
;
2267 Variable
->Volatile
= FALSE
;
2270 Fvb
= mVariableModuleGlobal
->FvbInstance
;
2273 // Tricky part: Use scratch data area at the end of volatile variable store
2274 // as a temporary storage.
2276 NextVariable
= GetEndPointer ((VARIABLE_STORE_HEADER
*) ((UINTN
) mVariableModuleGlobal
->VariableGlobal
.VolatileVariableBase
));
2277 ScratchSize
= mVariableModuleGlobal
->ScratchBufferSize
;
2278 SetMem (NextVariable
, ScratchSize
, 0xff);
2281 if (Variable
->CurrPtr
!= NULL
) {
2283 // Update/Delete existing variable.
2287 // If AtRuntime and the variable is Volatile and Runtime Access,
2288 // the volatile is ReadOnly, and SetVariable should be aborted and
2289 // return EFI_WRITE_PROTECTED.
2291 if (Variable
->Volatile
) {
2292 Status
= EFI_WRITE_PROTECTED
;
2296 // Only variable that have NV attributes can be updated/deleted in Runtime.
2298 if ((CacheVariable
->CurrPtr
->Attributes
& EFI_VARIABLE_NON_VOLATILE
) == 0) {
2299 Status
= EFI_INVALID_PARAMETER
;
2304 // Only variable that have RT attributes can be updated/deleted in Runtime.
2306 if ((CacheVariable
->CurrPtr
->Attributes
& EFI_VARIABLE_RUNTIME_ACCESS
) == 0) {
2307 Status
= EFI_INVALID_PARAMETER
;
2313 // Setting a data variable with no access, or zero DataSize attributes
2314 // causes it to be deleted.
2315 // When the EFI_VARIABLE_APPEND_WRITE attribute is set, DataSize of zero will
2316 // not delete the variable.
2318 if ((((Attributes
& EFI_VARIABLE_APPEND_WRITE
) == 0) && (DataSize
== 0))|| ((Attributes
& (EFI_VARIABLE_RUNTIME_ACCESS
| EFI_VARIABLE_BOOTSERVICE_ACCESS
)) == 0)) {
2319 if (Variable
->InDeletedTransitionPtr
!= NULL
) {
2321 // Both ADDED and IN_DELETED_TRANSITION variable are present,
2322 // set IN_DELETED_TRANSITION one to DELETED state first.
2324 ASSERT (CacheVariable
->InDeletedTransitionPtr
!= NULL
);
2325 State
= CacheVariable
->InDeletedTransitionPtr
->State
;
2326 State
&= VAR_DELETED
;
2327 Status
= UpdateVariableStore (
2328 &mVariableModuleGlobal
->VariableGlobal
,
2332 (UINTN
) &Variable
->InDeletedTransitionPtr
->State
,
2336 if (!EFI_ERROR (Status
)) {
2337 if (!Variable
->Volatile
) {
2338 CacheVariable
->InDeletedTransitionPtr
->State
= State
;
2345 State
= CacheVariable
->CurrPtr
->State
;
2346 State
&= VAR_DELETED
;
2348 Status
= UpdateVariableStore (
2349 &mVariableModuleGlobal
->VariableGlobal
,
2353 (UINTN
) &Variable
->CurrPtr
->State
,
2357 if (!EFI_ERROR (Status
)) {
2358 UpdateVariableInfo (VariableName
, VendorGuid
, Variable
->Volatile
, FALSE
, FALSE
, TRUE
, FALSE
);
2359 if (!Variable
->Volatile
) {
2360 CacheVariable
->CurrPtr
->State
= State
;
2361 FlushHobVariableToFlash (VariableName
, VendorGuid
);
2367 // If the variable is marked valid, and the same data has been passed in,
2368 // then return to the caller immediately.
2370 if (DataSizeOfVariable (CacheVariable
->CurrPtr
) == DataSize
&&
2371 (CompareMem (Data
, GetVariableDataPtr (CacheVariable
->CurrPtr
), DataSize
) == 0) &&
2372 ((Attributes
& EFI_VARIABLE_APPEND_WRITE
) == 0) &&
2373 (TimeStamp
== NULL
)) {
2375 // Variable content unchanged and no need to update timestamp, just return.
2377 UpdateVariableInfo (VariableName
, VendorGuid
, Variable
->Volatile
, FALSE
, TRUE
, FALSE
, FALSE
);
2378 Status
= EFI_SUCCESS
;
2380 } else if ((CacheVariable
->CurrPtr
->State
== VAR_ADDED
) ||
2381 (CacheVariable
->CurrPtr
->State
== (VAR_ADDED
& VAR_IN_DELETED_TRANSITION
))) {
2384 // EFI_VARIABLE_APPEND_WRITE attribute only effects for existing variable.
2386 if ((Attributes
& EFI_VARIABLE_APPEND_WRITE
) != 0) {
2388 // NOTE: From 0 to DataOffset of NextVariable is reserved for Variable Header and Name.
2389 // From DataOffset of NextVariable is to save the existing variable data.
2391 DataOffset
= GetVariableDataOffset (CacheVariable
->CurrPtr
);
2392 BufferForMerge
= (UINT8
*) ((UINTN
) NextVariable
+ DataOffset
);
2393 CopyMem (BufferForMerge
, (UINT8
*) ((UINTN
) CacheVariable
->CurrPtr
+ DataOffset
), DataSizeOfVariable (CacheVariable
->CurrPtr
));
2396 // Set Max Common/Auth Variable Data Size as default MaxDataSize.
2398 if ((Attributes
& VARIABLE_ATTRIBUTE_AT_AW
) != 0) {
2399 MaxDataSize
= mVariableModuleGlobal
->MaxAuthVariableSize
- DataOffset
;
2401 MaxDataSize
= mVariableModuleGlobal
->MaxVariableSize
- DataOffset
;
2405 // Append the new data to the end of existing data.
2406 // Max Harware error record variable data size is different from common/auth variable.
2408 if ((Attributes
& EFI_VARIABLE_HARDWARE_ERROR_RECORD
) == EFI_VARIABLE_HARDWARE_ERROR_RECORD
) {
2409 MaxDataSize
= PcdGet32 (PcdMaxHardwareErrorVariableSize
) - DataOffset
;
2412 if (DataSizeOfVariable (CacheVariable
->CurrPtr
) + DataSize
> MaxDataSize
) {
2414 // Existing data size + new data size exceed maximum variable size limitation.
2416 Status
= EFI_INVALID_PARAMETER
;
2419 CopyMem ((UINT8
*) ((UINTN
) BufferForMerge
+ DataSizeOfVariable (CacheVariable
->CurrPtr
)), Data
, DataSize
);
2420 MergedBufSize
= DataSizeOfVariable (CacheVariable
->CurrPtr
) + DataSize
;
2423 // BufferForMerge(from DataOffset of NextVariable) has included the merged existing and new data.
2425 Data
= BufferForMerge
;
2426 DataSize
= MergedBufSize
;
2431 // Mark the old variable as in delete transition.
2433 State
= CacheVariable
->CurrPtr
->State
;
2434 State
&= VAR_IN_DELETED_TRANSITION
;
2436 Status
= UpdateVariableStore (
2437 &mVariableModuleGlobal
->VariableGlobal
,
2441 (UINTN
) &Variable
->CurrPtr
->State
,
2445 if (EFI_ERROR (Status
)) {
2448 if (!Variable
->Volatile
) {
2449 CacheVariable
->CurrPtr
->State
= State
;
2454 // Not found existing variable. Create a new variable.
2457 if ((DataSize
== 0) && ((Attributes
& EFI_VARIABLE_APPEND_WRITE
) != 0)) {
2458 Status
= EFI_SUCCESS
;
2463 // Make sure we are trying to create a new variable.
2464 // Setting a data variable with zero DataSize or no access attributes means to delete it.
2466 if (DataSize
== 0 || (Attributes
& (EFI_VARIABLE_RUNTIME_ACCESS
| EFI_VARIABLE_BOOTSERVICE_ACCESS
)) == 0) {
2467 Status
= EFI_NOT_FOUND
;
2472 // Only variable have NV|RT attribute can be created in Runtime.
2475 (((Attributes
& EFI_VARIABLE_RUNTIME_ACCESS
) == 0) || ((Attributes
& EFI_VARIABLE_NON_VOLATILE
) == 0))) {
2476 Status
= EFI_INVALID_PARAMETER
;
2482 // Function part - create a new variable and copy the data.
2483 // Both update a variable and create a variable will come here.
2485 NextVariable
->StartId
= VARIABLE_DATA
;
2487 // NextVariable->State = VAR_ADDED;
2489 NextVariable
->Reserved
= 0;
2490 if (mVariableModuleGlobal
->VariableGlobal
.AuthFormat
) {
2491 AuthVariable
= (AUTHENTICATED_VARIABLE_HEADER
*) NextVariable
;
2492 AuthVariable
->PubKeyIndex
= KeyIndex
;
2493 AuthVariable
->MonotonicCount
= MonotonicCount
;
2494 ZeroMem (&AuthVariable
->TimeStamp
, sizeof (EFI_TIME
));
2496 if (((Attributes
& EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS
) != 0) &&
2497 (TimeStamp
!= NULL
)) {
2498 if ((Attributes
& EFI_VARIABLE_APPEND_WRITE
) == 0) {
2499 CopyMem (&AuthVariable
->TimeStamp
, TimeStamp
, sizeof (EFI_TIME
));
2502 // In the case when the EFI_VARIABLE_APPEND_WRITE attribute is set, only
2503 // when the new TimeStamp value is later than the current timestamp associated
2504 // with the variable, we need associate the new timestamp with the updated value.
2506 if (Variable
->CurrPtr
!= NULL
) {
2507 if (VariableCompareTimeStampInternal (&(((AUTHENTICATED_VARIABLE_HEADER
*) CacheVariable
->CurrPtr
)->TimeStamp
), TimeStamp
)) {
2508 CopyMem (&AuthVariable
->TimeStamp
, TimeStamp
, sizeof (EFI_TIME
));
2516 // The EFI_VARIABLE_APPEND_WRITE attribute will never be set in the returned
2517 // Attributes bitmask parameter of a GetVariable() call.
2519 NextVariable
->Attributes
= Attributes
& (~EFI_VARIABLE_APPEND_WRITE
);
2521 VarNameOffset
= GetVariableHeaderSize ();
2522 VarNameSize
= StrSize (VariableName
);
2524 (UINT8
*) ((UINTN
) NextVariable
+ VarNameOffset
),
2528 VarDataOffset
= VarNameOffset
+ VarNameSize
+ GET_PAD_SIZE (VarNameSize
);
2531 // If DataReady is TRUE, it means the variable data has been saved into
2532 // NextVariable during EFI_VARIABLE_APPEND_WRITE operation preparation.
2536 (UINT8
*) ((UINTN
) NextVariable
+ VarDataOffset
),
2542 CopyMem (GetVendorGuidPtr (NextVariable
), VendorGuid
, sizeof (EFI_GUID
));
2544 // There will be pad bytes after Data, the NextVariable->NameSize and
2545 // NextVariable->DataSize should not include pad size so that variable
2546 // service can get actual size in GetVariable.
2548 SetNameSizeOfVariable (NextVariable
, VarNameSize
);
2549 SetDataSizeOfVariable (NextVariable
, DataSize
);
2552 // The actual size of the variable that stores in storage should
2553 // include pad size.
2555 VarSize
= VarDataOffset
+ DataSize
+ GET_PAD_SIZE (DataSize
);
2556 if ((Attributes
& EFI_VARIABLE_NON_VOLATILE
) != 0) {
2558 // Create a nonvolatile variable.
2562 IsCommonVariable
= FALSE
;
2563 IsCommonUserVariable
= FALSE
;
2564 if ((Attributes
& EFI_VARIABLE_HARDWARE_ERROR_RECORD
) == 0) {
2565 IsCommonVariable
= TRUE
;
2566 IsCommonUserVariable
= IsUserVariable (NextVariable
);
2568 if ((((Attributes
& EFI_VARIABLE_HARDWARE_ERROR_RECORD
) != 0)
2569 && ((VarSize
+ mVariableModuleGlobal
->HwErrVariableTotalSize
) > PcdGet32 (PcdHwErrStorageSize
)))
2570 || (IsCommonVariable
&& ((VarSize
+ mVariableModuleGlobal
->CommonVariableTotalSize
) > mVariableModuleGlobal
->CommonVariableSpace
))
2571 || (IsCommonVariable
&& AtRuntime () && ((VarSize
+ mVariableModuleGlobal
->CommonVariableTotalSize
) > mVariableModuleGlobal
->CommonRuntimeVariableSpace
))
2572 || (IsCommonUserVariable
&& ((VarSize
+ mVariableModuleGlobal
->CommonUserVariableTotalSize
) > mVariableModuleGlobal
->CommonMaxUserVariableSpace
))) {
2574 if (IsCommonUserVariable
&& ((VarSize
+ mVariableModuleGlobal
->CommonUserVariableTotalSize
) > mVariableModuleGlobal
->CommonMaxUserVariableSpace
)) {
2575 RecordVarErrorFlag (VAR_ERROR_FLAG_USER_ERROR
, VariableName
, VendorGuid
, Attributes
, VarSize
);
2577 if (IsCommonVariable
&& ((VarSize
+ mVariableModuleGlobal
->CommonVariableTotalSize
) > mVariableModuleGlobal
->CommonRuntimeVariableSpace
)) {
2578 RecordVarErrorFlag (VAR_ERROR_FLAG_SYSTEM_ERROR
, VariableName
, VendorGuid
, Attributes
, VarSize
);
2580 Status
= EFI_OUT_OF_RESOURCES
;
2584 // Perform garbage collection & reclaim operation, and integrate the new variable at the same time.
2587 mVariableModuleGlobal
->VariableGlobal
.NonVolatileVariableBase
,
2588 &mVariableModuleGlobal
->NonVolatileLastVariableOffset
,
2592 HEADER_ALIGN (VarSize
)
2594 if (!EFI_ERROR (Status
)) {
2596 // The new variable has been integrated successfully during reclaiming.
2598 if (Variable
->CurrPtr
!= NULL
) {
2599 CacheVariable
->CurrPtr
= (VARIABLE_HEADER
*)((UINTN
) CacheVariable
->StartPtr
+ ((UINTN
) Variable
->CurrPtr
- (UINTN
) Variable
->StartPtr
));
2600 CacheVariable
->InDeletedTransitionPtr
= NULL
;
2602 UpdateVariableInfo (VariableName
, VendorGuid
, FALSE
, FALSE
, TRUE
, FALSE
, FALSE
);
2603 FlushHobVariableToFlash (VariableName
, VendorGuid
);
2605 if (IsCommonUserVariable
&& ((VarSize
+ mVariableModuleGlobal
->CommonUserVariableTotalSize
) > mVariableModuleGlobal
->CommonMaxUserVariableSpace
)) {
2606 RecordVarErrorFlag (VAR_ERROR_FLAG_USER_ERROR
, VariableName
, VendorGuid
, Attributes
, VarSize
);
2608 if (IsCommonVariable
&& ((VarSize
+ mVariableModuleGlobal
->CommonVariableTotalSize
) > mVariableModuleGlobal
->CommonVariableSpace
)) {
2609 RecordVarErrorFlag (VAR_ERROR_FLAG_SYSTEM_ERROR
, VariableName
, VendorGuid
, Attributes
, VarSize
);
2616 // 1. Write variable header
2617 // 2. Set variable state to header valid
2618 // 3. Write variable data
2619 // 4. Set variable state to valid
2624 CacheOffset
= mVariableModuleGlobal
->NonVolatileLastVariableOffset
;
2625 Status
= UpdateVariableStore (
2626 &mVariableModuleGlobal
->VariableGlobal
,
2630 mVariableModuleGlobal
->NonVolatileLastVariableOffset
,
2631 (UINT32
) GetVariableHeaderSize (),
2632 (UINT8
*) NextVariable
2635 if (EFI_ERROR (Status
)) {
2642 NextVariable
->State
= VAR_HEADER_VALID_ONLY
;
2643 Status
= UpdateVariableStore (
2644 &mVariableModuleGlobal
->VariableGlobal
,
2648 mVariableModuleGlobal
->NonVolatileLastVariableOffset
+ OFFSET_OF (VARIABLE_HEADER
, State
),
2650 &NextVariable
->State
2653 if (EFI_ERROR (Status
)) {
2659 Status
= UpdateVariableStore (
2660 &mVariableModuleGlobal
->VariableGlobal
,
2664 mVariableModuleGlobal
->NonVolatileLastVariableOffset
+ GetVariableHeaderSize (),
2665 (UINT32
) (VarSize
- GetVariableHeaderSize ()),
2666 (UINT8
*) NextVariable
+ GetVariableHeaderSize ()
2669 if (EFI_ERROR (Status
)) {
2675 NextVariable
->State
= VAR_ADDED
;
2676 Status
= UpdateVariableStore (
2677 &mVariableModuleGlobal
->VariableGlobal
,
2681 mVariableModuleGlobal
->NonVolatileLastVariableOffset
+ OFFSET_OF (VARIABLE_HEADER
, State
),
2683 &NextVariable
->State
2686 if (EFI_ERROR (Status
)) {
2690 mVariableModuleGlobal
->NonVolatileLastVariableOffset
+= HEADER_ALIGN (VarSize
);
2692 if ((Attributes
& EFI_VARIABLE_HARDWARE_ERROR_RECORD
) != 0) {
2693 mVariableModuleGlobal
->HwErrVariableTotalSize
+= HEADER_ALIGN (VarSize
);
2695 mVariableModuleGlobal
->CommonVariableTotalSize
+= HEADER_ALIGN (VarSize
);
2696 if (IsCommonUserVariable
) {
2697 mVariableModuleGlobal
->CommonUserVariableTotalSize
+= HEADER_ALIGN (VarSize
);
2701 // update the memory copy of Flash region.
2703 CopyMem ((UINT8
*)mNvVariableCache
+ CacheOffset
, (UINT8
*)NextVariable
, VarSize
);
2706 // Create a volatile variable.
2710 if ((UINT32
) (VarSize
+ mVariableModuleGlobal
->VolatileLastVariableOffset
) >
2711 ((VARIABLE_STORE_HEADER
*) ((UINTN
) (mVariableModuleGlobal
->VariableGlobal
.VolatileVariableBase
)))->Size
) {
2713 // Perform garbage collection & reclaim operation, and integrate the new variable at the same time.
2716 mVariableModuleGlobal
->VariableGlobal
.VolatileVariableBase
,
2717 &mVariableModuleGlobal
->VolatileLastVariableOffset
,
2721 HEADER_ALIGN (VarSize
)
2723 if (!EFI_ERROR (Status
)) {
2725 // The new variable has been integrated successfully during reclaiming.
2727 if (Variable
->CurrPtr
!= NULL
) {
2728 CacheVariable
->CurrPtr
= (VARIABLE_HEADER
*)((UINTN
) CacheVariable
->StartPtr
+ ((UINTN
) Variable
->CurrPtr
- (UINTN
) Variable
->StartPtr
));
2729 CacheVariable
->InDeletedTransitionPtr
= NULL
;
2731 UpdateVariableInfo (VariableName
, VendorGuid
, TRUE
, FALSE
, TRUE
, FALSE
, FALSE
);
2736 NextVariable
->State
= VAR_ADDED
;
2737 Status
= UpdateVariableStore (
2738 &mVariableModuleGlobal
->VariableGlobal
,
2742 mVariableModuleGlobal
->VolatileLastVariableOffset
,
2744 (UINT8
*) NextVariable
2747 if (EFI_ERROR (Status
)) {
2751 mVariableModuleGlobal
->VolatileLastVariableOffset
+= HEADER_ALIGN (VarSize
);
2755 // Mark the old variable as deleted.
2757 if (!EFI_ERROR (Status
) && Variable
->CurrPtr
!= NULL
) {
2758 if (Variable
->InDeletedTransitionPtr
!= NULL
) {
2760 // Both ADDED and IN_DELETED_TRANSITION old variable are present,
2761 // set IN_DELETED_TRANSITION one to DELETED state first.
2763 ASSERT (CacheVariable
->InDeletedTransitionPtr
!= NULL
);
2764 State
= CacheVariable
->InDeletedTransitionPtr
->State
;
2765 State
&= VAR_DELETED
;
2766 Status
= UpdateVariableStore (
2767 &mVariableModuleGlobal
->VariableGlobal
,
2771 (UINTN
) &Variable
->InDeletedTransitionPtr
->State
,
2775 if (!EFI_ERROR (Status
)) {
2776 if (!Variable
->Volatile
) {
2777 CacheVariable
->InDeletedTransitionPtr
->State
= State
;
2784 State
= Variable
->CurrPtr
->State
;
2785 State
&= VAR_DELETED
;
2787 Status
= UpdateVariableStore (
2788 &mVariableModuleGlobal
->VariableGlobal
,
2792 (UINTN
) &Variable
->CurrPtr
->State
,
2796 if (!EFI_ERROR (Status
) && !Variable
->Volatile
) {
2797 CacheVariable
->CurrPtr
->State
= State
;
2801 if (!EFI_ERROR (Status
)) {
2802 UpdateVariableInfo (VariableName
, VendorGuid
, Volatile
, FALSE
, TRUE
, FALSE
, FALSE
);
2804 FlushHobVariableToFlash (VariableName
, VendorGuid
);
2814 This code finds variable in storage blocks (Volatile or Non-Volatile).
2816 Caution: This function may receive untrusted input.
2817 This function may be invoked in SMM mode, and datasize is external input.
2818 This function will do basic validation, before parse the data.
2820 @param VariableName Name of Variable to be found.
2821 @param VendorGuid Variable vendor GUID.
2822 @param Attributes Attribute value of the variable found.
2823 @param DataSize Size of Data found. If size is less than the
2824 data, this value contains the required size.
2825 @param Data The buffer to return the contents of the variable. May be NULL
2826 with a zero DataSize in order to determine the size buffer needed.
2828 @return EFI_INVALID_PARAMETER Invalid parameter.
2829 @return EFI_SUCCESS Find the specified variable.
2830 @return EFI_NOT_FOUND Not found.
2831 @return EFI_BUFFER_TO_SMALL DataSize is too small for the result.
2836 VariableServiceGetVariable (
2837 IN CHAR16
*VariableName
,
2838 IN EFI_GUID
*VendorGuid
,
2839 OUT UINT32
*Attributes OPTIONAL
,
2840 IN OUT UINTN
*DataSize
,
2841 OUT VOID
*Data OPTIONAL
2845 VARIABLE_POINTER_TRACK Variable
;
2848 if (VariableName
== NULL
|| VendorGuid
== NULL
|| DataSize
== NULL
) {
2849 return EFI_INVALID_PARAMETER
;
2852 AcquireLockOnlyAtBootTime(&mVariableModuleGlobal
->VariableGlobal
.VariableServicesLock
);
2854 Status
= FindVariable (VariableName
, VendorGuid
, &Variable
, &mVariableModuleGlobal
->VariableGlobal
, FALSE
);
2855 if (Variable
.CurrPtr
== NULL
|| EFI_ERROR (Status
)) {
2862 VarDataSize
= DataSizeOfVariable (Variable
.CurrPtr
);
2863 ASSERT (VarDataSize
!= 0);
2865 if (*DataSize
>= VarDataSize
) {
2867 Status
= EFI_INVALID_PARAMETER
;
2871 CopyMem (Data
, GetVariableDataPtr (Variable
.CurrPtr
), VarDataSize
);
2872 if (Attributes
!= NULL
) {
2873 *Attributes
= Variable
.CurrPtr
->Attributes
;
2876 *DataSize
= VarDataSize
;
2877 UpdateVariableInfo (VariableName
, VendorGuid
, Variable
.Volatile
, TRUE
, FALSE
, FALSE
, FALSE
);
2879 Status
= EFI_SUCCESS
;
2882 *DataSize
= VarDataSize
;
2883 Status
= EFI_BUFFER_TOO_SMALL
;
2888 ReleaseLockOnlyAtBootTime (&mVariableModuleGlobal
->VariableGlobal
.VariableServicesLock
);
2893 This code Finds the Next available variable.
2895 Caution: This function may receive untrusted input.
2896 This function may be invoked in SMM mode. This function will do basic validation, before parse the data.
2898 @param[in] VariableName Pointer to variable name.
2899 @param[in] VendorGuid Variable Vendor Guid.
2900 @param[out] VariablePtr Pointer to variable header address.
2902 @return EFI_SUCCESS Find the specified variable.
2903 @return EFI_NOT_FOUND Not found.
2908 VariableServiceGetNextVariableInternal (
2909 IN CHAR16
*VariableName
,
2910 IN EFI_GUID
*VendorGuid
,
2911 OUT VARIABLE_HEADER
**VariablePtr
2914 VARIABLE_STORE_TYPE Type
;
2915 VARIABLE_POINTER_TRACK Variable
;
2916 VARIABLE_POINTER_TRACK VariableInHob
;
2917 VARIABLE_POINTER_TRACK VariablePtrTrack
;
2919 VARIABLE_STORE_HEADER
*VariableStoreHeader
[VariableStoreTypeMax
];
2921 Status
= FindVariable (VariableName
, VendorGuid
, &Variable
, &mVariableModuleGlobal
->VariableGlobal
, FALSE
);
2922 if (Variable
.CurrPtr
== NULL
|| EFI_ERROR (Status
)) {
2926 if (VariableName
[0] != 0) {
2928 // If variable name is not NULL, get next variable.
2930 Variable
.CurrPtr
= GetNextVariablePtr (Variable
.CurrPtr
);
2934 // 0: Volatile, 1: HOB, 2: Non-Volatile.
2935 // The index and attributes mapping must be kept in this order as FindVariable
2936 // makes use of this mapping to implement search algorithm.
2938 VariableStoreHeader
[VariableStoreTypeVolatile
] = (VARIABLE_STORE_HEADER
*) (UINTN
) mVariableModuleGlobal
->VariableGlobal
.VolatileVariableBase
;
2939 VariableStoreHeader
[VariableStoreTypeHob
] = (VARIABLE_STORE_HEADER
*) (UINTN
) mVariableModuleGlobal
->VariableGlobal
.HobVariableBase
;
2940 VariableStoreHeader
[VariableStoreTypeNv
] = mNvVariableCache
;
2944 // Switch from Volatile to HOB, to Non-Volatile.
2946 while (!IsValidVariableHeader (Variable
.CurrPtr
, Variable
.EndPtr
)) {
2948 // Find current storage index
2950 for (Type
= (VARIABLE_STORE_TYPE
) 0; Type
< VariableStoreTypeMax
; Type
++) {
2951 if ((VariableStoreHeader
[Type
] != NULL
) && (Variable
.StartPtr
== GetStartPointer (VariableStoreHeader
[Type
]))) {
2955 ASSERT (Type
< VariableStoreTypeMax
);
2957 // Switch to next storage
2959 for (Type
++; Type
< VariableStoreTypeMax
; Type
++) {
2960 if (VariableStoreHeader
[Type
] != NULL
) {
2965 // Capture the case that
2966 // 1. current storage is the last one, or
2967 // 2. no further storage
2969 if (Type
== VariableStoreTypeMax
) {
2970 Status
= EFI_NOT_FOUND
;
2973 Variable
.StartPtr
= GetStartPointer (VariableStoreHeader
[Type
]);
2974 Variable
.EndPtr
= GetEndPointer (VariableStoreHeader
[Type
]);
2975 Variable
.CurrPtr
= Variable
.StartPtr
;
2979 // Variable is found
2981 if (Variable
.CurrPtr
->State
== VAR_ADDED
|| Variable
.CurrPtr
->State
== (VAR_IN_DELETED_TRANSITION
& VAR_ADDED
)) {
2982 if (!AtRuntime () || ((Variable
.CurrPtr
->Attributes
& EFI_VARIABLE_RUNTIME_ACCESS
) != 0)) {
2983 if (Variable
.CurrPtr
->State
== (VAR_IN_DELETED_TRANSITION
& VAR_ADDED
)) {
2985 // If it is a IN_DELETED_TRANSITION variable,
2986 // and there is also a same ADDED one at the same time,
2989 VariablePtrTrack
.StartPtr
= Variable
.StartPtr
;
2990 VariablePtrTrack
.EndPtr
= Variable
.EndPtr
;
2991 Status
= FindVariableEx (
2992 GetVariableNamePtr (Variable
.CurrPtr
),
2993 GetVendorGuidPtr (Variable
.CurrPtr
),
2997 if (!EFI_ERROR (Status
) && VariablePtrTrack
.CurrPtr
->State
== VAR_ADDED
) {
2998 Variable
.CurrPtr
= GetNextVariablePtr (Variable
.CurrPtr
);
3004 // Don't return NV variable when HOB overrides it
3006 if ((VariableStoreHeader
[VariableStoreTypeHob
] != NULL
) && (VariableStoreHeader
[VariableStoreTypeNv
] != NULL
) &&
3007 (Variable
.StartPtr
== GetStartPointer (VariableStoreHeader
[VariableStoreTypeNv
]))
3009 VariableInHob
.StartPtr
= GetStartPointer (VariableStoreHeader
[VariableStoreTypeHob
]);
3010 VariableInHob
.EndPtr
= GetEndPointer (VariableStoreHeader
[VariableStoreTypeHob
]);
3011 Status
= FindVariableEx (
3012 GetVariableNamePtr (Variable
.CurrPtr
),
3013 GetVendorGuidPtr (Variable
.CurrPtr
),
3017 if (!EFI_ERROR (Status
)) {
3018 Variable
.CurrPtr
= GetNextVariablePtr (Variable
.CurrPtr
);
3023 *VariablePtr
= Variable
.CurrPtr
;
3024 Status
= EFI_SUCCESS
;
3029 Variable
.CurrPtr
= GetNextVariablePtr (Variable
.CurrPtr
);
3038 This code Finds the Next available variable.
3040 Caution: This function may receive untrusted input.
3041 This function may be invoked in SMM mode. This function will do basic validation, before parse the data.
3043 @param VariableNameSize Size of the variable name.
3044 @param VariableName Pointer to variable name.
3045 @param VendorGuid Variable Vendor Guid.
3047 @return EFI_INVALID_PARAMETER Invalid parameter.
3048 @return EFI_SUCCESS Find the specified variable.
3049 @return EFI_NOT_FOUND Not found.
3050 @return EFI_BUFFER_TO_SMALL DataSize is too small for the result.
3055 VariableServiceGetNextVariableName (
3056 IN OUT UINTN
*VariableNameSize
,
3057 IN OUT CHAR16
*VariableName
,
3058 IN OUT EFI_GUID
*VendorGuid
3063 VARIABLE_HEADER
*VariablePtr
;
3065 if (VariableNameSize
== NULL
|| VariableName
== NULL
|| VendorGuid
== NULL
) {
3066 return EFI_INVALID_PARAMETER
;
3069 AcquireLockOnlyAtBootTime(&mVariableModuleGlobal
->VariableGlobal
.VariableServicesLock
);
3071 Status
= VariableServiceGetNextVariableInternal (VariableName
, VendorGuid
, &VariablePtr
);
3072 if (!EFI_ERROR (Status
)) {
3073 VarNameSize
= NameSizeOfVariable (VariablePtr
);
3074 ASSERT (VarNameSize
!= 0);
3075 if (VarNameSize
<= *VariableNameSize
) {
3076 CopyMem (VariableName
, GetVariableNamePtr (VariablePtr
), VarNameSize
);
3077 CopyMem (VendorGuid
, GetVendorGuidPtr (VariablePtr
), sizeof (EFI_GUID
));
3078 Status
= EFI_SUCCESS
;
3080 Status
= EFI_BUFFER_TOO_SMALL
;
3083 *VariableNameSize
= VarNameSize
;
3086 ReleaseLockOnlyAtBootTime (&mVariableModuleGlobal
->VariableGlobal
.VariableServicesLock
);
3092 This code sets variable in storage blocks (Volatile or Non-Volatile).
3094 Caution: This function may receive untrusted input.
3095 This function may be invoked in SMM mode, and datasize and data are external input.
3096 This function will do basic validation, before parse the data.
3097 This function will parse the authentication carefully to avoid security issues, like
3098 buffer overflow, integer overflow.
3099 This function will check attribute carefully to avoid authentication bypass.
3101 @param VariableName Name of Variable to be found.
3102 @param VendorGuid Variable vendor GUID.
3103 @param Attributes Attribute value of the variable found
3104 @param DataSize Size of Data found. If size is less than the
3105 data, this value contains the required size.
3106 @param Data Data pointer.
3108 @return EFI_INVALID_PARAMETER Invalid parameter.
3109 @return EFI_SUCCESS Set successfully.
3110 @return EFI_OUT_OF_RESOURCES Resource not enough to set variable.
3111 @return EFI_NOT_FOUND Not found.
3112 @return EFI_WRITE_PROTECTED Variable is read-only.
3117 VariableServiceSetVariable (
3118 IN CHAR16
*VariableName
,
3119 IN EFI_GUID
*VendorGuid
,
3120 IN UINT32 Attributes
,
3125 VARIABLE_POINTER_TRACK Variable
;
3127 VARIABLE_HEADER
*NextVariable
;
3128 EFI_PHYSICAL_ADDRESS Point
;
3132 // Check input parameters.
3134 if (VariableName
== NULL
|| VariableName
[0] == 0 || VendorGuid
== NULL
) {
3135 return EFI_INVALID_PARAMETER
;
3138 if (DataSize
!= 0 && Data
== NULL
) {
3139 return EFI_INVALID_PARAMETER
;
3143 // Check for reserverd bit in variable attribute.
3145 if ((Attributes
& (~EFI_VARIABLE_ATTRIBUTES_MASK
)) != 0) {
3146 return EFI_INVALID_PARAMETER
;
3150 // Make sure if runtime bit is set, boot service bit is set also.
3152 if ((Attributes
& (EFI_VARIABLE_RUNTIME_ACCESS
| EFI_VARIABLE_BOOTSERVICE_ACCESS
)) == EFI_VARIABLE_RUNTIME_ACCESS
) {
3153 return EFI_INVALID_PARAMETER
;
3154 } else if ((Attributes
& VARIABLE_ATTRIBUTE_AT_AW
) != 0) {
3155 if (!mVariableModuleGlobal
->VariableGlobal
.AuthSupport
) {
3157 // Not support authenticated variable write.
3159 return EFI_INVALID_PARAMETER
;
3161 } else if ((Attributes
& EFI_VARIABLE_HARDWARE_ERROR_RECORD
) != 0) {
3162 if (PcdGet32 (PcdHwErrStorageSize
) == 0) {
3164 // Not support harware error record variable variable.
3166 return EFI_INVALID_PARAMETER
;
3171 // EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS and EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS attribute
3172 // cannot be set both.
3174 if (((Attributes
& EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS
) == EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS
)
3175 && ((Attributes
& EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS
) == EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS
)) {
3176 return EFI_INVALID_PARAMETER
;
3179 if ((Attributes
& EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS
) == EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS
) {
3180 if (DataSize
< AUTHINFO_SIZE
) {
3182 // Try to write Authenticated Variable without AuthInfo.
3184 return EFI_SECURITY_VIOLATION
;
3186 PayloadSize
= DataSize
- AUTHINFO_SIZE
;
3187 } else if ((Attributes
& EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS
) == EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS
) {
3189 // Sanity check for EFI_VARIABLE_AUTHENTICATION_2 descriptor.
3191 if (DataSize
< OFFSET_OF_AUTHINFO2_CERT_DATA
||
3192 ((EFI_VARIABLE_AUTHENTICATION_2
*) Data
)->AuthInfo
.Hdr
.dwLength
> DataSize
- (OFFSET_OF (EFI_VARIABLE_AUTHENTICATION_2
, AuthInfo
)) ||
3193 ((EFI_VARIABLE_AUTHENTICATION_2
*) Data
)->AuthInfo
.Hdr
.dwLength
< OFFSET_OF (WIN_CERTIFICATE_UEFI_GUID
, CertData
)) {
3194 return EFI_SECURITY_VIOLATION
;
3196 PayloadSize
= DataSize
- AUTHINFO2_SIZE (Data
);
3198 PayloadSize
= DataSize
;
3201 if ((UINTN
)(~0) - PayloadSize
< StrSize(VariableName
)){
3203 // Prevent whole variable size overflow
3205 return EFI_INVALID_PARAMETER
;
3209 // The size of the VariableName, including the Unicode Null in bytes plus
3210 // the DataSize is limited to maximum size of PcdGet32 (PcdMaxHardwareErrorVariableSize)
3211 // bytes for HwErrRec#### variable.
3213 if ((Attributes
& EFI_VARIABLE_HARDWARE_ERROR_RECORD
) == EFI_VARIABLE_HARDWARE_ERROR_RECORD
) {
3214 if (StrSize (VariableName
) + PayloadSize
> PcdGet32 (PcdMaxHardwareErrorVariableSize
) - GetVariableHeaderSize ()) {
3215 return EFI_INVALID_PARAMETER
;
3219 // The size of the VariableName, including the Unicode Null in bytes plus
3220 // the DataSize is limited to maximum size of Max(Auth)VariableSize bytes.
3222 if ((Attributes
& VARIABLE_ATTRIBUTE_AT_AW
) != 0) {
3223 if (StrSize (VariableName
) + PayloadSize
> mVariableModuleGlobal
->MaxAuthVariableSize
- GetVariableHeaderSize ()) {
3224 return EFI_INVALID_PARAMETER
;
3227 if (StrSize (VariableName
) + PayloadSize
> mVariableModuleGlobal
->MaxVariableSize
- GetVariableHeaderSize ()) {
3228 return EFI_INVALID_PARAMETER
;
3234 // Special Handling for MOR Lock variable.
3236 Status
= SetVariableCheckHandlerMor (VariableName
, VendorGuid
, Attributes
, PayloadSize
, (VOID
*) ((UINTN
) Data
+ DataSize
- PayloadSize
));
3237 if (Status
== EFI_ALREADY_STARTED
) {
3239 // EFI_ALREADY_STARTED means the SetVariable() action is handled inside of SetVariableCheckHandlerMor().
3240 // Variable driver can just return SUCCESS.
3244 if (EFI_ERROR (Status
)) {
3248 Status
= VarCheckLibSetVariableCheck (VariableName
, VendorGuid
, Attributes
, PayloadSize
, (VOID
*) ((UINTN
) Data
+ DataSize
- PayloadSize
), mRequestSource
);
3249 if (EFI_ERROR (Status
)) {
3253 AcquireLockOnlyAtBootTime(&mVariableModuleGlobal
->VariableGlobal
.VariableServicesLock
);
3256 // Consider reentrant in MCA/INIT/NMI. It needs be reupdated.
3258 if (1 < InterlockedIncrement (&mVariableModuleGlobal
->VariableGlobal
.ReentrantState
)) {
3259 Point
= mVariableModuleGlobal
->VariableGlobal
.NonVolatileVariableBase
;
3261 // Parse non-volatile variable data and get last variable offset.
3263 NextVariable
= GetStartPointer ((VARIABLE_STORE_HEADER
*) (UINTN
) Point
);
3264 while (IsValidVariableHeader (NextVariable
, GetEndPointer ((VARIABLE_STORE_HEADER
*) (UINTN
) Point
))) {
3265 NextVariable
= GetNextVariablePtr (NextVariable
);
3267 mVariableModuleGlobal
->NonVolatileLastVariableOffset
= (UINTN
) NextVariable
- (UINTN
) Point
;
3271 // Check whether the input variable is already existed.
3273 Status
= FindVariable (VariableName
, VendorGuid
, &Variable
, &mVariableModuleGlobal
->VariableGlobal
, TRUE
);
3274 if (!EFI_ERROR (Status
)) {
3275 if (((Variable
.CurrPtr
->Attributes
& EFI_VARIABLE_RUNTIME_ACCESS
) == 0) && AtRuntime ()) {
3276 Status
= EFI_WRITE_PROTECTED
;
3279 if (Attributes
!= 0 && (Attributes
& (~EFI_VARIABLE_APPEND_WRITE
)) != Variable
.CurrPtr
->Attributes
) {
3281 // If a preexisting variable is rewritten with different attributes, SetVariable() shall not
3282 // modify the variable and shall return EFI_INVALID_PARAMETER. Two exceptions to this rule:
3283 // 1. No access attributes specified
3284 // 2. The only attribute differing is EFI_VARIABLE_APPEND_WRITE
3286 Status
= EFI_INVALID_PARAMETER
;
3287 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
));
3292 if (!FeaturePcdGet (PcdUefiVariableDefaultLangDeprecate
)) {
3294 // Hook the operation of setting PlatformLangCodes/PlatformLang and LangCodes/Lang.
3296 Status
= AutoUpdateLangVariable (VariableName
, Data
, DataSize
);
3297 if (EFI_ERROR (Status
)) {
3299 // The auto update operation failed, directly return to avoid inconsistency between PlatformLang and Lang.
3305 if (mVariableModuleGlobal
->VariableGlobal
.AuthSupport
) {
3306 Status
= AuthVariableLibProcessVariable (VariableName
, VendorGuid
, Data
, DataSize
, Attributes
);
3308 Status
= UpdateVariable (VariableName
, VendorGuid
, Data
, DataSize
, Attributes
, 0, 0, &Variable
, NULL
);
3312 InterlockedDecrement (&mVariableModuleGlobal
->VariableGlobal
.ReentrantState
);
3313 ReleaseLockOnlyAtBootTime (&mVariableModuleGlobal
->VariableGlobal
.VariableServicesLock
);
3315 if (!AtRuntime ()) {
3316 if (!EFI_ERROR (Status
)) {
3329 This code returns information about the EFI variables.
3331 Caution: This function may receive untrusted input.
3332 This function may be invoked in SMM mode. This function will do basic validation, before parse the data.
3334 @param Attributes Attributes bitmask to specify the type of variables
3335 on which to return information.
3336 @param MaximumVariableStorageSize Pointer to the maximum size of the storage space available
3337 for the EFI variables associated with the attributes specified.
3338 @param RemainingVariableStorageSize Pointer to the remaining size of the storage space available
3339 for EFI variables associated with the attributes specified.
3340 @param MaximumVariableSize Pointer to the maximum size of an individual EFI variables
3341 associated with the attributes specified.
3343 @return EFI_SUCCESS Query successfully.
3348 VariableServiceQueryVariableInfoInternal (
3349 IN UINT32 Attributes
,
3350 OUT UINT64
*MaximumVariableStorageSize
,
3351 OUT UINT64
*RemainingVariableStorageSize
,
3352 OUT UINT64
*MaximumVariableSize
3355 VARIABLE_HEADER
*Variable
;
3356 VARIABLE_HEADER
*NextVariable
;
3357 UINT64 VariableSize
;
3358 VARIABLE_STORE_HEADER
*VariableStoreHeader
;
3359 UINT64 CommonVariableTotalSize
;
3360 UINT64 HwErrVariableTotalSize
;
3362 VARIABLE_POINTER_TRACK VariablePtrTrack
;
3364 CommonVariableTotalSize
= 0;
3365 HwErrVariableTotalSize
= 0;
3367 if((Attributes
& EFI_VARIABLE_NON_VOLATILE
) == 0) {
3369 // Query is Volatile related.
3371 VariableStoreHeader
= (VARIABLE_STORE_HEADER
*) ((UINTN
) mVariableModuleGlobal
->VariableGlobal
.VolatileVariableBase
);
3374 // Query is Non-Volatile related.
3376 VariableStoreHeader
= mNvVariableCache
;
3380 // Now let's fill *MaximumVariableStorageSize *RemainingVariableStorageSize
3381 // with the storage size (excluding the storage header size).
3383 *MaximumVariableStorageSize
= VariableStoreHeader
->Size
- sizeof (VARIABLE_STORE_HEADER
);
3386 // Harware error record variable needs larger size.
3388 if ((Attributes
& (EFI_VARIABLE_NON_VOLATILE
| EFI_VARIABLE_HARDWARE_ERROR_RECORD
)) == (EFI_VARIABLE_NON_VOLATILE
| EFI_VARIABLE_HARDWARE_ERROR_RECORD
)) {
3389 *MaximumVariableStorageSize
= PcdGet32 (PcdHwErrStorageSize
);
3390 *MaximumVariableSize
= PcdGet32 (PcdMaxHardwareErrorVariableSize
) - GetVariableHeaderSize ();
3392 if ((Attributes
& EFI_VARIABLE_NON_VOLATILE
) != 0) {
3394 *MaximumVariableStorageSize
= mVariableModuleGlobal
->CommonRuntimeVariableSpace
;
3396 *MaximumVariableStorageSize
= mVariableModuleGlobal
->CommonVariableSpace
;
3401 // Let *MaximumVariableSize be Max(Auth)VariableSize with the exception of the variable header size.
3403 if ((Attributes
& VARIABLE_ATTRIBUTE_AT_AW
) != 0) {
3404 *MaximumVariableSize
= mVariableModuleGlobal
->MaxAuthVariableSize
- GetVariableHeaderSize ();
3406 *MaximumVariableSize
= mVariableModuleGlobal
->MaxVariableSize
- GetVariableHeaderSize ();
3411 // Point to the starting address of the variables.
3413 Variable
= GetStartPointer (VariableStoreHeader
);
3416 // Now walk through the related variable store.
3418 while (IsValidVariableHeader (Variable
, GetEndPointer (VariableStoreHeader
))) {
3419 NextVariable
= GetNextVariablePtr (Variable
);
3420 VariableSize
= (UINT64
) (UINTN
) NextVariable
- (UINT64
) (UINTN
) Variable
;
3424 // We don't take the state of the variables in mind
3425 // when calculating RemainingVariableStorageSize,
3426 // since the space occupied by variables not marked with
3427 // VAR_ADDED is not allowed to be reclaimed in Runtime.
3429 if ((Variable
->Attributes
& EFI_VARIABLE_HARDWARE_ERROR_RECORD
) == EFI_VARIABLE_HARDWARE_ERROR_RECORD
) {
3430 HwErrVariableTotalSize
+= VariableSize
;
3432 CommonVariableTotalSize
+= VariableSize
;
3436 // Only care about Variables with State VAR_ADDED, because
3437 // the space not marked as VAR_ADDED is reclaimable now.
3439 if (Variable
->State
== VAR_ADDED
) {
3440 if ((Variable
->Attributes
& EFI_VARIABLE_HARDWARE_ERROR_RECORD
) == EFI_VARIABLE_HARDWARE_ERROR_RECORD
) {
3441 HwErrVariableTotalSize
+= VariableSize
;
3443 CommonVariableTotalSize
+= VariableSize
;
3445 } else if (Variable
->State
== (VAR_IN_DELETED_TRANSITION
& VAR_ADDED
)) {
3447 // If it is a IN_DELETED_TRANSITION variable,
3448 // and there is not also a same ADDED one at the same time,
3449 // this IN_DELETED_TRANSITION variable is valid.
3451 VariablePtrTrack
.StartPtr
= GetStartPointer (VariableStoreHeader
);
3452 VariablePtrTrack
.EndPtr
= GetEndPointer (VariableStoreHeader
);
3453 Status
= FindVariableEx (
3454 GetVariableNamePtr (Variable
),
3455 GetVendorGuidPtr (Variable
),
3459 if (!EFI_ERROR (Status
) && VariablePtrTrack
.CurrPtr
->State
!= VAR_ADDED
) {
3460 if ((Variable
->Attributes
& EFI_VARIABLE_HARDWARE_ERROR_RECORD
) == EFI_VARIABLE_HARDWARE_ERROR_RECORD
) {
3461 HwErrVariableTotalSize
+= VariableSize
;
3463 CommonVariableTotalSize
+= VariableSize
;
3470 // Go to the next one.
3472 Variable
= NextVariable
;
3475 if ((Attributes
& EFI_VARIABLE_HARDWARE_ERROR_RECORD
) == EFI_VARIABLE_HARDWARE_ERROR_RECORD
){
3476 *RemainingVariableStorageSize
= *MaximumVariableStorageSize
- HwErrVariableTotalSize
;
3478 if (*MaximumVariableStorageSize
< CommonVariableTotalSize
) {
3479 *RemainingVariableStorageSize
= 0;
3481 *RemainingVariableStorageSize
= *MaximumVariableStorageSize
- CommonVariableTotalSize
;
3485 if (*RemainingVariableStorageSize
< GetVariableHeaderSize ()) {
3486 *MaximumVariableSize
= 0;
3487 } else if ((*RemainingVariableStorageSize
- GetVariableHeaderSize ()) < *MaximumVariableSize
) {
3488 *MaximumVariableSize
= *RemainingVariableStorageSize
- GetVariableHeaderSize ();
3496 This code returns information about the EFI variables.
3498 Caution: This function may receive untrusted input.
3499 This function may be invoked in SMM mode. This function will do basic validation, before parse the data.
3501 @param Attributes Attributes bitmask to specify the type of variables
3502 on which to return information.
3503 @param MaximumVariableStorageSize Pointer to the maximum size of the storage space available
3504 for the EFI variables associated with the attributes specified.
3505 @param RemainingVariableStorageSize Pointer to the remaining size of the storage space available
3506 for EFI variables associated with the attributes specified.
3507 @param MaximumVariableSize Pointer to the maximum size of an individual EFI variables
3508 associated with the attributes specified.
3510 @return EFI_INVALID_PARAMETER An invalid combination of attribute bits was supplied.
3511 @return EFI_SUCCESS Query successfully.
3512 @return EFI_UNSUPPORTED The attribute is not supported on this platform.
3517 VariableServiceQueryVariableInfo (
3518 IN UINT32 Attributes
,
3519 OUT UINT64
*MaximumVariableStorageSize
,
3520 OUT UINT64
*RemainingVariableStorageSize
,
3521 OUT UINT64
*MaximumVariableSize
3526 if(MaximumVariableStorageSize
== NULL
|| RemainingVariableStorageSize
== NULL
|| MaximumVariableSize
== NULL
|| Attributes
== 0) {
3527 return EFI_INVALID_PARAMETER
;
3530 if ((Attributes
& EFI_VARIABLE_ATTRIBUTES_MASK
) == 0) {
3532 // Make sure the Attributes combination is supported by the platform.
3534 return EFI_UNSUPPORTED
;
3535 } else if ((Attributes
& (EFI_VARIABLE_RUNTIME_ACCESS
| EFI_VARIABLE_BOOTSERVICE_ACCESS
)) == EFI_VARIABLE_RUNTIME_ACCESS
) {
3537 // Make sure if runtime bit is set, boot service bit is set also.
3539 return EFI_INVALID_PARAMETER
;
3540 } else if (AtRuntime () && ((Attributes
& EFI_VARIABLE_RUNTIME_ACCESS
) == 0)) {
3542 // Make sure RT Attribute is set if we are in Runtime phase.
3544 return EFI_INVALID_PARAMETER
;
3545 } else if ((Attributes
& (EFI_VARIABLE_NON_VOLATILE
| EFI_VARIABLE_HARDWARE_ERROR_RECORD
)) == EFI_VARIABLE_HARDWARE_ERROR_RECORD
) {
3547 // Make sure Hw Attribute is set with NV.
3549 return EFI_INVALID_PARAMETER
;
3550 } else if ((Attributes
& VARIABLE_ATTRIBUTE_AT_AW
) != 0) {
3551 if (!mVariableModuleGlobal
->VariableGlobal
.AuthSupport
) {
3553 // Not support authenticated variable write.
3555 return EFI_UNSUPPORTED
;
3557 } else if ((Attributes
& EFI_VARIABLE_HARDWARE_ERROR_RECORD
) != 0) {
3558 if (PcdGet32 (PcdHwErrStorageSize
) == 0) {
3560 // Not support harware error record variable variable.
3562 return EFI_UNSUPPORTED
;
3566 AcquireLockOnlyAtBootTime(&mVariableModuleGlobal
->VariableGlobal
.VariableServicesLock
);
3568 Status
= VariableServiceQueryVariableInfoInternal (
3570 MaximumVariableStorageSize
,
3571 RemainingVariableStorageSize
,
3575 ReleaseLockOnlyAtBootTime (&mVariableModuleGlobal
->VariableGlobal
.VariableServicesLock
);
3580 This function reclaims variable storage if free size is below the threshold.
3582 Caution: This function may be invoked at SMM mode.
3583 Care must be taken to make sure not security issue.
3592 UINTN RemainingCommonRuntimeVariableSpace
;
3593 UINTN RemainingHwErrVariableSpace
;
3594 STATIC BOOLEAN Reclaimed
;
3597 // This function will be called only once at EndOfDxe or ReadyToBoot event.
3604 Status
= EFI_SUCCESS
;
3606 if (mVariableModuleGlobal
->CommonRuntimeVariableSpace
< mVariableModuleGlobal
->CommonVariableTotalSize
) {
3607 RemainingCommonRuntimeVariableSpace
= 0;
3609 RemainingCommonRuntimeVariableSpace
= mVariableModuleGlobal
->CommonRuntimeVariableSpace
- mVariableModuleGlobal
->CommonVariableTotalSize
;
3612 RemainingHwErrVariableSpace
= PcdGet32 (PcdHwErrStorageSize
) - mVariableModuleGlobal
->HwErrVariableTotalSize
;
3615 // Check if the free area is below a threshold.
3617 if (((RemainingCommonRuntimeVariableSpace
< mVariableModuleGlobal
->MaxVariableSize
) ||
3618 (RemainingCommonRuntimeVariableSpace
< mVariableModuleGlobal
->MaxAuthVariableSize
)) ||
3619 ((PcdGet32 (PcdHwErrStorageSize
) != 0) &&
3620 (RemainingHwErrVariableSpace
< PcdGet32 (PcdMaxHardwareErrorVariableSize
)))){
3622 mVariableModuleGlobal
->VariableGlobal
.NonVolatileVariableBase
,
3623 &mVariableModuleGlobal
->NonVolatileLastVariableOffset
,
3629 ASSERT_EFI_ERROR (Status
);
3634 Get non-volatile maximum variable size.
3636 @return Non-volatile maximum variable size.
3640 GetNonVolatileMaxVariableSize (
3644 if (PcdGet32 (PcdHwErrStorageSize
) != 0) {
3645 return MAX (MAX (PcdGet32 (PcdMaxVariableSize
), PcdGet32 (PcdMaxAuthVariableSize
)),
3646 PcdGet32 (PcdMaxHardwareErrorVariableSize
));
3648 return MAX (PcdGet32 (PcdMaxVariableSize
), PcdGet32 (PcdMaxAuthVariableSize
));
3653 Init non-volatile variable store.
3655 @param[out] NvFvHeader Output pointer to non-volatile FV header address.
3657 @retval EFI_SUCCESS Function successfully executed.
3658 @retval EFI_OUT_OF_RESOURCES Fail to allocate enough memory resource.
3659 @retval EFI_VOLUME_CORRUPTED Variable Store or Firmware Volume for Variable Store is corrupted.
3663 InitNonVolatileVariableStore (
3664 OUT EFI_FIRMWARE_VOLUME_HEADER
**NvFvHeader
3667 EFI_FIRMWARE_VOLUME_HEADER
*FvHeader
;
3668 VARIABLE_HEADER
*Variable
;
3669 VARIABLE_HEADER
*NextVariable
;
3670 EFI_PHYSICAL_ADDRESS VariableStoreBase
;
3671 UINT64 VariableStoreLength
;
3673 EFI_HOB_GUID_TYPE
*GuidHob
;
3674 EFI_PHYSICAL_ADDRESS NvStorageBase
;
3675 UINT8
*NvStorageData
;
3676 UINT32 NvStorageSize
;
3677 FAULT_TOLERANT_WRITE_LAST_WRITE_DATA
*FtwLastWriteData
;
3678 UINT32 BackUpOffset
;
3680 UINT32 HwErrStorageSize
;
3681 UINT32 MaxUserNvVariableSpaceSize
;
3682 UINT32 BoottimeReservedNvVariableSpaceSize
;
3686 mVariableModuleGlobal
->FvbInstance
= NULL
;
3689 // Allocate runtime memory used for a memory copy of the FLASH region.
3690 // Keep the memory and the FLASH in sync as updates occur.
3692 NvStorageSize
= PcdGet32 (PcdFlashNvStorageVariableSize
);
3693 NvStorageData
= AllocateRuntimeZeroPool (NvStorageSize
);
3694 if (NvStorageData
== NULL
) {
3695 return EFI_OUT_OF_RESOURCES
;
3698 NvStorageBase
= (EFI_PHYSICAL_ADDRESS
) PcdGet64 (PcdFlashNvStorageVariableBase64
);
3699 if (NvStorageBase
== 0) {
3700 NvStorageBase
= (EFI_PHYSICAL_ADDRESS
) PcdGet32 (PcdFlashNvStorageVariableBase
);
3703 // Copy NV storage data to the memory buffer.
3705 CopyMem (NvStorageData
, (UINT8
*) (UINTN
) NvStorageBase
, NvStorageSize
);
3707 Status
= GetFtwProtocol ((VOID
**)&FtwProtocol
);
3709 // If FTW protocol has been installed, no need to check FTW last write data hob.
3711 if (EFI_ERROR (Status
)) {
3713 // Check the FTW last write data hob.
3715 GuidHob
= GetFirstGuidHob (&gEdkiiFaultTolerantWriteGuid
);
3716 if (GuidHob
!= NULL
) {
3717 FtwLastWriteData
= (FAULT_TOLERANT_WRITE_LAST_WRITE_DATA
*) GET_GUID_HOB_DATA (GuidHob
);
3718 if (FtwLastWriteData
->TargetAddress
== NvStorageBase
) {
3719 DEBUG ((EFI_D_INFO
, "Variable: NV storage is backed up in spare block: 0x%x\n", (UINTN
) FtwLastWriteData
->SpareAddress
));
3721 // Copy the backed up NV storage data to the memory buffer from spare block.
3723 CopyMem (NvStorageData
, (UINT8
*) (UINTN
) (FtwLastWriteData
->SpareAddress
), NvStorageSize
);
3724 } else if ((FtwLastWriteData
->TargetAddress
> NvStorageBase
) &&
3725 (FtwLastWriteData
->TargetAddress
< (NvStorageBase
+ NvStorageSize
))) {
3727 // Flash NV storage from the Offset is backed up in spare block.
3729 BackUpOffset
= (UINT32
) (FtwLastWriteData
->TargetAddress
- NvStorageBase
);
3730 BackUpSize
= NvStorageSize
- BackUpOffset
;
3731 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
));
3733 // Copy the partial backed up NV storage data to the memory buffer from spare block.
3735 CopyMem (NvStorageData
+ BackUpOffset
, (UINT8
*) (UINTN
) FtwLastWriteData
->SpareAddress
, BackUpSize
);
3740 FvHeader
= (EFI_FIRMWARE_VOLUME_HEADER
*) NvStorageData
;
3743 // Check if the Firmware Volume is not corrupted
3745 if ((FvHeader
->Signature
!= EFI_FVH_SIGNATURE
) || (!CompareGuid (&gEfiSystemNvDataFvGuid
, &FvHeader
->FileSystemGuid
))) {
3746 FreePool (NvStorageData
);
3747 DEBUG ((EFI_D_ERROR
, "Firmware Volume for Variable Store is corrupted\n"));
3748 return EFI_VOLUME_CORRUPTED
;
3751 VariableStoreBase
= (EFI_PHYSICAL_ADDRESS
) ((UINTN
) FvHeader
+ FvHeader
->HeaderLength
);
3752 VariableStoreLength
= (UINT64
) (NvStorageSize
- FvHeader
->HeaderLength
);
3754 mNvFvHeaderCache
= FvHeader
;
3755 mVariableModuleGlobal
->VariableGlobal
.NonVolatileVariableBase
= VariableStoreBase
;
3756 mNvVariableCache
= (VARIABLE_STORE_HEADER
*) (UINTN
) VariableStoreBase
;
3757 if (GetVariableStoreStatus (mNvVariableCache
) != EfiValid
) {
3758 FreePool (NvStorageData
);
3759 mNvFvHeaderCache
= NULL
;
3760 mNvVariableCache
= NULL
;
3761 DEBUG((EFI_D_ERROR
, "Variable Store header is corrupted\n"));
3762 return EFI_VOLUME_CORRUPTED
;
3764 ASSERT(mNvVariableCache
->Size
== VariableStoreLength
);
3766 ASSERT (sizeof (VARIABLE_STORE_HEADER
) <= VariableStoreLength
);
3768 mVariableModuleGlobal
->VariableGlobal
.AuthFormat
= (BOOLEAN
)(CompareGuid (&mNvVariableCache
->Signature
, &gEfiAuthenticatedVariableGuid
));
3770 HwErrStorageSize
= PcdGet32 (PcdHwErrStorageSize
);
3771 MaxUserNvVariableSpaceSize
= PcdGet32 (PcdMaxUserNvVariableSpaceSize
);
3772 BoottimeReservedNvVariableSpaceSize
= PcdGet32 (PcdBoottimeReservedNvVariableSpaceSize
);
3775 // Note that in EdkII variable driver implementation, Hardware Error Record type variable
3776 // is stored with common variable in the same NV region. So the platform integrator should
3777 // ensure that the value of PcdHwErrStorageSize is less than the value of
3778 // (VariableStoreLength - sizeof (VARIABLE_STORE_HEADER)).
3780 ASSERT (HwErrStorageSize
< (VariableStoreLength
- sizeof (VARIABLE_STORE_HEADER
)));
3782 // Ensure that the value of PcdMaxUserNvVariableSpaceSize is less than the value of
3783 // (VariableStoreLength - sizeof (VARIABLE_STORE_HEADER)) - PcdGet32 (PcdHwErrStorageSize).
3785 ASSERT (MaxUserNvVariableSpaceSize
< (VariableStoreLength
- sizeof (VARIABLE_STORE_HEADER
) - HwErrStorageSize
));
3787 // Ensure that the value of PcdBoottimeReservedNvVariableSpaceSize is less than the value of
3788 // (VariableStoreLength - sizeof (VARIABLE_STORE_HEADER)) - PcdGet32 (PcdHwErrStorageSize).
3790 ASSERT (BoottimeReservedNvVariableSpaceSize
< (VariableStoreLength
- sizeof (VARIABLE_STORE_HEADER
) - HwErrStorageSize
));
3792 mVariableModuleGlobal
->CommonVariableSpace
= ((UINTN
) VariableStoreLength
- sizeof (VARIABLE_STORE_HEADER
) - HwErrStorageSize
);
3793 mVariableModuleGlobal
->CommonMaxUserVariableSpace
= ((MaxUserNvVariableSpaceSize
!= 0) ? MaxUserNvVariableSpaceSize
: mVariableModuleGlobal
->CommonVariableSpace
);
3794 mVariableModuleGlobal
->CommonRuntimeVariableSpace
= mVariableModuleGlobal
->CommonVariableSpace
- BoottimeReservedNvVariableSpaceSize
;
3796 DEBUG ((EFI_D_INFO
, "Variable driver common space: 0x%x 0x%x 0x%x\n", mVariableModuleGlobal
->CommonVariableSpace
, mVariableModuleGlobal
->CommonMaxUserVariableSpace
, mVariableModuleGlobal
->CommonRuntimeVariableSpace
));
3799 // The max NV variable size should be < (VariableStoreLength - sizeof (VARIABLE_STORE_HEADER)).
3801 ASSERT (GetNonVolatileMaxVariableSize () < (VariableStoreLength
- sizeof (VARIABLE_STORE_HEADER
)));
3803 mVariableModuleGlobal
->MaxVariableSize
= PcdGet32 (PcdMaxVariableSize
);
3804 mVariableModuleGlobal
->MaxAuthVariableSize
= ((PcdGet32 (PcdMaxAuthVariableSize
) != 0) ? PcdGet32 (PcdMaxAuthVariableSize
) : mVariableModuleGlobal
->MaxVariableSize
);
3807 // Parse non-volatile variable data and get last variable offset.
3809 Variable
= GetStartPointer ((VARIABLE_STORE_HEADER
*)(UINTN
)VariableStoreBase
);
3810 while (IsValidVariableHeader (Variable
, GetEndPointer ((VARIABLE_STORE_HEADER
*)(UINTN
)VariableStoreBase
))) {
3811 NextVariable
= GetNextVariablePtr (Variable
);
3812 VariableSize
= (UINTN
) NextVariable
- (UINTN
) Variable
;
3813 if ((Variable
->Attributes
& (EFI_VARIABLE_NON_VOLATILE
| EFI_VARIABLE_HARDWARE_ERROR_RECORD
)) == (EFI_VARIABLE_NON_VOLATILE
| EFI_VARIABLE_HARDWARE_ERROR_RECORD
)) {
3814 mVariableModuleGlobal
->HwErrVariableTotalSize
+= VariableSize
;
3816 mVariableModuleGlobal
->CommonVariableTotalSize
+= VariableSize
;
3819 Variable
= NextVariable
;
3821 mVariableModuleGlobal
->NonVolatileLastVariableOffset
= (UINTN
) Variable
- (UINTN
) VariableStoreBase
;
3823 *NvFvHeader
= FvHeader
;
3828 Flush the HOB variable to flash.
3830 @param[in] VariableName Name of variable has been updated or deleted.
3831 @param[in] VendorGuid Guid of variable has been updated or deleted.
3835 FlushHobVariableToFlash (
3836 IN CHAR16
*VariableName
,
3837 IN EFI_GUID
*VendorGuid
3841 VARIABLE_STORE_HEADER
*VariableStoreHeader
;
3842 VARIABLE_HEADER
*Variable
;
3844 VARIABLE_POINTER_TRACK VariablePtrTrack
;
3850 // Flush the HOB variable to flash.
3852 if (mVariableModuleGlobal
->VariableGlobal
.HobVariableBase
!= 0) {
3853 VariableStoreHeader
= (VARIABLE_STORE_HEADER
*) (UINTN
) mVariableModuleGlobal
->VariableGlobal
.HobVariableBase
;
3855 // Set HobVariableBase to 0, it can avoid SetVariable to call back.
3857 mVariableModuleGlobal
->VariableGlobal
.HobVariableBase
= 0;
3858 for ( Variable
= GetStartPointer (VariableStoreHeader
)
3859 ; IsValidVariableHeader (Variable
, GetEndPointer (VariableStoreHeader
))
3860 ; Variable
= GetNextVariablePtr (Variable
)
3862 if (Variable
->State
!= VAR_ADDED
) {
3864 // The HOB variable has been set to DELETED state in local.
3868 ASSERT ((Variable
->Attributes
& EFI_VARIABLE_NON_VOLATILE
) != 0);
3869 if (VendorGuid
== NULL
|| VariableName
== NULL
||
3870 !CompareGuid (VendorGuid
, GetVendorGuidPtr (Variable
)) ||
3871 StrCmp (VariableName
, GetVariableNamePtr (Variable
)) != 0) {
3872 VariableData
= GetVariableDataPtr (Variable
);
3873 FindVariable (GetVariableNamePtr (Variable
), GetVendorGuidPtr (Variable
), &VariablePtrTrack
, &mVariableModuleGlobal
->VariableGlobal
, FALSE
);
3874 Status
= UpdateVariable (
3875 GetVariableNamePtr (Variable
),
3876 GetVendorGuidPtr (Variable
),
3878 DataSizeOfVariable (Variable
),
3879 Variable
->Attributes
,
3885 DEBUG ((EFI_D_INFO
, "Variable driver flush the HOB variable to flash: %g %s %r\n", GetVendorGuidPtr (Variable
), GetVariableNamePtr (Variable
), Status
));
3888 // The updated or deleted variable is matched with this HOB variable.
3889 // Don't break here because we will try to set other HOB variables
3890 // since this variable could be set successfully.
3892 Status
= EFI_SUCCESS
;
3894 if (!EFI_ERROR (Status
)) {
3896 // If set variable successful, or the updated or deleted variable is matched with the HOB variable,
3897 // set the HOB variable to DELETED state in local.
3899 DEBUG ((EFI_D_INFO
, "Variable driver set the HOB variable to DELETED state in local: %g %s\n", GetVendorGuidPtr (Variable
), GetVariableNamePtr (Variable
)));
3900 Variable
->State
&= VAR_DELETED
;
3907 // We still have HOB variable(s) not flushed in flash.
3909 mVariableModuleGlobal
->VariableGlobal
.HobVariableBase
= (EFI_PHYSICAL_ADDRESS
) (UINTN
) VariableStoreHeader
;
3912 // All HOB variables have been flushed in flash.
3914 DEBUG ((EFI_D_INFO
, "Variable driver: all HOB variables have been flushed in flash.\n"));
3915 if (!AtRuntime ()) {
3916 FreePool ((VOID
*) VariableStoreHeader
);
3924 Initializes variable write service after FTW was ready.
3926 @retval EFI_SUCCESS Function successfully executed.
3927 @retval Others Fail to initialize the variable service.
3931 VariableWriteServiceInitialize (
3938 EFI_PHYSICAL_ADDRESS VariableStoreBase
;
3939 EFI_PHYSICAL_ADDRESS NvStorageBase
;
3940 VARIABLE_ENTRY_PROPERTY
*VariableEntry
;
3942 AcquireLockOnlyAtBootTime(&mVariableModuleGlobal
->VariableGlobal
.VariableServicesLock
);
3944 NvStorageBase
= (EFI_PHYSICAL_ADDRESS
) PcdGet64 (PcdFlashNvStorageVariableBase64
);
3945 if (NvStorageBase
== 0) {
3946 NvStorageBase
= (EFI_PHYSICAL_ADDRESS
) PcdGet32 (PcdFlashNvStorageVariableBase
);
3948 VariableStoreBase
= NvStorageBase
+ (mNvFvHeaderCache
->HeaderLength
);
3951 // Let NonVolatileVariableBase point to flash variable store base directly after FTW ready.
3953 mVariableModuleGlobal
->VariableGlobal
.NonVolatileVariableBase
= VariableStoreBase
;
3956 // Check if the free area is really free.
3958 for (Index
= mVariableModuleGlobal
->NonVolatileLastVariableOffset
; Index
< mNvVariableCache
->Size
; Index
++) {
3959 Data
= ((UINT8
*) mNvVariableCache
)[Index
];
3962 // There must be something wrong in variable store, do reclaim operation.
3965 mVariableModuleGlobal
->VariableGlobal
.NonVolatileVariableBase
,
3966 &mVariableModuleGlobal
->NonVolatileLastVariableOffset
,
3972 if (EFI_ERROR (Status
)) {
3973 ReleaseLockOnlyAtBootTime (&mVariableModuleGlobal
->VariableGlobal
.VariableServicesLock
);
3980 FlushHobVariableToFlash (NULL
, NULL
);
3982 Status
= EFI_SUCCESS
;
3983 ZeroMem (&mAuthContextOut
, sizeof (mAuthContextOut
));
3984 if (mVariableModuleGlobal
->VariableGlobal
.AuthFormat
) {
3986 // Authenticated variable initialize.
3988 mAuthContextIn
.StructSize
= sizeof (AUTH_VAR_LIB_CONTEXT_IN
);
3989 mAuthContextIn
.MaxAuthVariableSize
= mVariableModuleGlobal
->MaxAuthVariableSize
- GetVariableHeaderSize ();
3990 Status
= AuthVariableLibInitialize (&mAuthContextIn
, &mAuthContextOut
);
3991 if (!EFI_ERROR (Status
)) {
3992 DEBUG ((EFI_D_INFO
, "Variable driver will work with auth variable support!\n"));
3993 mVariableModuleGlobal
->VariableGlobal
.AuthSupport
= TRUE
;
3994 if (mAuthContextOut
.AuthVarEntry
!= NULL
) {
3995 for (Index
= 0; Index
< mAuthContextOut
.AuthVarEntryCount
; Index
++) {
3996 VariableEntry
= &mAuthContextOut
.AuthVarEntry
[Index
];
3997 Status
= VarCheckLibVariablePropertySet (
3998 VariableEntry
->Name
,
3999 VariableEntry
->Guid
,
4000 &VariableEntry
->VariableProperty
4002 ASSERT_EFI_ERROR (Status
);
4005 } else if (Status
== EFI_UNSUPPORTED
) {
4006 DEBUG ((EFI_D_INFO
, "NOTICE - AuthVariableLibInitialize() returns %r!\n", Status
));
4007 DEBUG ((EFI_D_INFO
, "Variable driver will continue to work without auth variable support!\n"));
4008 mVariableModuleGlobal
->VariableGlobal
.AuthSupport
= FALSE
;
4009 Status
= EFI_SUCCESS
;
4013 if (!EFI_ERROR (Status
)) {
4014 for (Index
= 0; Index
< sizeof (mVariableEntryProperty
) / sizeof (mVariableEntryProperty
[0]); Index
++) {
4015 VariableEntry
= &mVariableEntryProperty
[Index
];
4016 Status
= VarCheckLibVariablePropertySet (VariableEntry
->Name
, VariableEntry
->Guid
, &VariableEntry
->VariableProperty
);
4017 ASSERT_EFI_ERROR (Status
);
4021 ReleaseLockOnlyAtBootTime (&mVariableModuleGlobal
->VariableGlobal
.VariableServicesLock
);
4024 // Initialize MOR Lock variable.
4033 Initializes variable store area for non-volatile and volatile variable.
4035 @retval EFI_SUCCESS Function successfully executed.
4036 @retval EFI_OUT_OF_RESOURCES Fail to allocate enough memory resource.
4040 VariableCommonInitialize (
4045 VARIABLE_STORE_HEADER
*VolatileVariableStore
;
4046 VARIABLE_STORE_HEADER
*VariableStoreHeader
;
4047 UINT64 VariableStoreLength
;
4049 EFI_HOB_GUID_TYPE
*GuidHob
;
4050 EFI_GUID
*VariableGuid
;
4051 EFI_FIRMWARE_VOLUME_HEADER
*NvFvHeader
;
4054 // Allocate runtime memory for variable driver global structure.
4056 mVariableModuleGlobal
= AllocateRuntimeZeroPool (sizeof (VARIABLE_MODULE_GLOBAL
));
4057 if (mVariableModuleGlobal
== NULL
) {
4058 return EFI_OUT_OF_RESOURCES
;
4061 InitializeLock (&mVariableModuleGlobal
->VariableGlobal
.VariableServicesLock
, TPL_NOTIFY
);
4064 // Init non-volatile variable store.
4067 Status
= InitNonVolatileVariableStore (&NvFvHeader
);
4068 if (EFI_ERROR (Status
)) {
4069 FreePool (mVariableModuleGlobal
);
4074 // mVariableModuleGlobal->VariableGlobal.AuthFormat
4075 // has been initialized in InitNonVolatileVariableStore().
4077 if (mVariableModuleGlobal
->VariableGlobal
.AuthFormat
) {
4078 DEBUG ((EFI_D_INFO
, "Variable driver will work with auth variable format!\n"));
4080 // Set AuthSupport to FALSE first, VariableWriteServiceInitialize() will initialize it.
4082 mVariableModuleGlobal
->VariableGlobal
.AuthSupport
= FALSE
;
4083 VariableGuid
= &gEfiAuthenticatedVariableGuid
;
4085 DEBUG ((EFI_D_INFO
, "Variable driver will work without auth variable support!\n"));
4086 mVariableModuleGlobal
->VariableGlobal
.AuthSupport
= FALSE
;
4087 VariableGuid
= &gEfiVariableGuid
;
4091 // Get HOB variable store.
4093 GuidHob
= GetFirstGuidHob (VariableGuid
);
4094 if (GuidHob
!= NULL
) {
4095 VariableStoreHeader
= GET_GUID_HOB_DATA (GuidHob
);
4096 VariableStoreLength
= (UINT64
) (GuidHob
->Header
.HobLength
- sizeof (EFI_HOB_GUID_TYPE
));
4097 if (GetVariableStoreStatus (VariableStoreHeader
) == EfiValid
) {
4098 mVariableModuleGlobal
->VariableGlobal
.HobVariableBase
= (EFI_PHYSICAL_ADDRESS
) (UINTN
) AllocateRuntimeCopyPool ((UINTN
) VariableStoreLength
, (VOID
*) VariableStoreHeader
);
4099 if (mVariableModuleGlobal
->VariableGlobal
.HobVariableBase
== 0) {
4100 FreePool (NvFvHeader
);
4101 FreePool (mVariableModuleGlobal
);
4102 return EFI_OUT_OF_RESOURCES
;
4105 DEBUG ((EFI_D_ERROR
, "HOB Variable Store header is corrupted!\n"));
4110 // Allocate memory for volatile variable store, note that there is a scratch space to store scratch data.
4112 ScratchSize
= GetNonVolatileMaxVariableSize ();
4113 mVariableModuleGlobal
->ScratchBufferSize
= ScratchSize
;
4114 VolatileVariableStore
= AllocateRuntimePool (PcdGet32 (PcdVariableStoreSize
) + ScratchSize
);
4115 if (VolatileVariableStore
== NULL
) {
4116 if (mVariableModuleGlobal
->VariableGlobal
.HobVariableBase
!= 0) {
4117 FreePool ((VOID
*) (UINTN
) mVariableModuleGlobal
->VariableGlobal
.HobVariableBase
);
4119 FreePool (NvFvHeader
);
4120 FreePool (mVariableModuleGlobal
);
4121 return EFI_OUT_OF_RESOURCES
;
4124 SetMem (VolatileVariableStore
, PcdGet32 (PcdVariableStoreSize
) + ScratchSize
, 0xff);
4127 // Initialize Variable Specific Data.
4129 mVariableModuleGlobal
->VariableGlobal
.VolatileVariableBase
= (EFI_PHYSICAL_ADDRESS
) (UINTN
) VolatileVariableStore
;
4130 mVariableModuleGlobal
->VolatileLastVariableOffset
= (UINTN
) GetStartPointer (VolatileVariableStore
) - (UINTN
) VolatileVariableStore
;
4132 CopyGuid (&VolatileVariableStore
->Signature
, VariableGuid
);
4133 VolatileVariableStore
->Size
= PcdGet32 (PcdVariableStoreSize
);
4134 VolatileVariableStore
->Format
= VARIABLE_STORE_FORMATTED
;
4135 VolatileVariableStore
->State
= VARIABLE_STORE_HEALTHY
;
4136 VolatileVariableStore
->Reserved
= 0;
4137 VolatileVariableStore
->Reserved1
= 0;
4144 Get the proper fvb handle and/or fvb protocol by the given Flash address.
4146 @param[in] Address The Flash address.
4147 @param[out] FvbHandle In output, if it is not NULL, it points to the proper FVB handle.
4148 @param[out] FvbProtocol In output, if it is not NULL, it points to the proper FVB protocol.
4152 GetFvbInfoByAddress (
4153 IN EFI_PHYSICAL_ADDRESS Address
,
4154 OUT EFI_HANDLE
*FvbHandle OPTIONAL
,
4155 OUT EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
**FvbProtocol OPTIONAL
4159 EFI_HANDLE
*HandleBuffer
;
4162 EFI_PHYSICAL_ADDRESS FvbBaseAddress
;
4163 EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*Fvb
;
4164 EFI_FVB_ATTRIBUTES_2 Attributes
;
4166 UINTN NumberOfBlocks
;
4168 HandleBuffer
= NULL
;
4170 // Get all FVB handles.
4172 Status
= GetFvbCountAndBuffer (&HandleCount
, &HandleBuffer
);
4173 if (EFI_ERROR (Status
)) {
4174 return EFI_NOT_FOUND
;
4178 // Get the FVB to access variable store.
4181 for (Index
= 0; Index
< HandleCount
; Index
+= 1, Status
= EFI_NOT_FOUND
, Fvb
= NULL
) {
4182 Status
= GetFvbByHandle (HandleBuffer
[Index
], &Fvb
);
4183 if (EFI_ERROR (Status
)) {
4184 Status
= EFI_NOT_FOUND
;
4189 // Ensure this FVB protocol supported Write operation.
4191 Status
= Fvb
->GetAttributes (Fvb
, &Attributes
);
4192 if (EFI_ERROR (Status
) || ((Attributes
& EFI_FVB2_WRITE_STATUS
) == 0)) {
4197 // Compare the address and select the right one.
4199 Status
= Fvb
->GetPhysicalAddress (Fvb
, &FvbBaseAddress
);
4200 if (EFI_ERROR (Status
)) {
4205 // Assume one FVB has one type of BlockSize.
4207 Status
= Fvb
->GetBlockSize (Fvb
, 0, &BlockSize
, &NumberOfBlocks
);
4208 if (EFI_ERROR (Status
)) {
4212 if ((Address
>= FvbBaseAddress
) && (Address
< (FvbBaseAddress
+ BlockSize
* NumberOfBlocks
))) {
4213 if (FvbHandle
!= NULL
) {
4214 *FvbHandle
= HandleBuffer
[Index
];
4216 if (FvbProtocol
!= NULL
) {
4219 Status
= EFI_SUCCESS
;
4223 FreePool (HandleBuffer
);
4226 Status
= EFI_NOT_FOUND
;