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 - 2019, Intel Corporation. All rights reserved.<BR>
20 (C) Copyright 2015-2018 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.
37 /// For EmuNvMode == TRUE, it will be equal to NonVolatileVariableBase.
39 VARIABLE_STORE_HEADER
*mNvVariableCache
= NULL
;
42 /// Memory cache of Fv Header.
44 EFI_FIRMWARE_VOLUME_HEADER
*mNvFvHeaderCache
= NULL
;
47 /// The memory entry used for variable statistics data.
49 VARIABLE_INFO_ENTRY
*gVariableInfo
= NULL
;
52 /// The flag to indicate whether the platform has left the DXE phase of execution.
54 BOOLEAN mEndOfDxe
= FALSE
;
57 /// It indicates the var check request source.
58 /// In the implementation, DXE is regarded as untrusted, and SMM is trusted.
60 VAR_CHECK_REQUEST_SOURCE mRequestSource
= VarCheckFromUntrusted
;
63 // It will record the current boot error flag before EndOfDxe.
65 VAR_ERROR_FLAG mCurrentBootVarErrFlag
= VAR_ERROR_FLAG_NO_ERROR
;
67 VARIABLE_ENTRY_PROPERTY mVariableEntryProperty
[] = {
69 &gEdkiiVarErrorFlagGuid
,
72 VAR_CHECK_VARIABLE_PROPERTY_REVISION
,
73 VAR_CHECK_VARIABLE_PROPERTY_READ_ONLY
,
74 VARIABLE_ATTRIBUTE_NV_BS_RT
,
75 sizeof (VAR_ERROR_FLAG
),
76 sizeof (VAR_ERROR_FLAG
)
81 AUTH_VAR_LIB_CONTEXT_IN mAuthContextIn
= {
82 AUTH_VAR_LIB_CONTEXT_IN_STRUCT_VERSION
,
84 // StructSize, TO BE FILLED
88 // MaxAuthVariableSize, TO BE FILLED
91 VariableExLibFindVariable
,
92 VariableExLibFindNextVariable
,
93 VariableExLibUpdateVariable
,
94 VariableExLibGetScratchBuffer
,
95 VariableExLibCheckRemainingSpaceForConsistency
,
96 VariableExLibAtRuntime
,
99 AUTH_VAR_LIB_CONTEXT_OUT mAuthContextOut
;
102 Routine used to track statistical information about variable usage.
103 The data is stored in the EFI system table so it can be accessed later.
104 VariableInfo.efi can dump out the table. Only Boot Services variable
105 accesses are tracked by this code. The PcdVariableCollectStatistics
106 build flag controls if this feature is enabled.
108 A read that hits in the cache will have Read and Cache true for
109 the transaction. Data is allocated by this routine, but never
112 @param[in] VariableName Name of the Variable to track.
113 @param[in] VendorGuid Guid of the Variable to track.
114 @param[in] Volatile TRUE if volatile FALSE if non-volatile.
115 @param[in] Read TRUE if GetVariable() was called.
116 @param[in] Write TRUE if SetVariable() was called.
117 @param[in] Delete TRUE if deleted via SetVariable().
118 @param[in] Cache TRUE for a cache hit.
123 IN CHAR16
*VariableName
,
124 IN EFI_GUID
*VendorGuid
,
132 VARIABLE_INFO_ENTRY
*Entry
;
134 if (FeaturePcdGet (PcdVariableCollectStatistics
)) {
137 // Don't collect statistics at runtime.
141 if (gVariableInfo
== NULL
) {
143 // On the first call allocate a entry and place a pointer to it in
144 // the EFI System Table.
146 gVariableInfo
= AllocateZeroPool (sizeof (VARIABLE_INFO_ENTRY
));
147 ASSERT (gVariableInfo
!= NULL
);
149 CopyGuid (&gVariableInfo
->VendorGuid
, VendorGuid
);
150 gVariableInfo
->Name
= AllocateZeroPool (StrSize (VariableName
));
151 ASSERT (gVariableInfo
->Name
!= NULL
);
152 StrCpyS (gVariableInfo
->Name
, StrSize(VariableName
)/sizeof(CHAR16
), VariableName
);
153 gVariableInfo
->Volatile
= Volatile
;
157 for (Entry
= gVariableInfo
; Entry
!= NULL
; Entry
= Entry
->Next
) {
158 if (CompareGuid (VendorGuid
, &Entry
->VendorGuid
)) {
159 if (StrCmp (VariableName
, Entry
->Name
) == 0) {
167 Entry
->DeleteCount
++;
177 if (Entry
->Next
== NULL
) {
179 // If the entry is not in the table add it.
180 // Next iteration of the loop will fill in the data.
182 Entry
->Next
= AllocateZeroPool (sizeof (VARIABLE_INFO_ENTRY
));
183 ASSERT (Entry
->Next
!= NULL
);
185 CopyGuid (&Entry
->Next
->VendorGuid
, VendorGuid
);
186 Entry
->Next
->Name
= AllocateZeroPool (StrSize (VariableName
));
187 ASSERT (Entry
->Next
->Name
!= NULL
);
188 StrCpyS (Entry
->Next
->Name
, StrSize(VariableName
)/sizeof(CHAR16
), VariableName
);
189 Entry
->Next
->Volatile
= Volatile
;
199 This code checks if variable header is valid or not.
201 @param Variable Pointer to the Variable Header.
202 @param VariableStoreEnd Pointer to the Variable Store End.
204 @retval TRUE Variable header is valid.
205 @retval FALSE Variable header is not valid.
209 IsValidVariableHeader (
210 IN VARIABLE_HEADER
*Variable
,
211 IN VARIABLE_HEADER
*VariableStoreEnd
214 if ((Variable
== NULL
) || (Variable
>= VariableStoreEnd
) || (Variable
->StartId
!= VARIABLE_DATA
)) {
216 // Variable is NULL or has reached the end of variable store,
217 // or the StartId is not correct.
228 This function writes data to the FWH at the correct LBA even if the LBAs
231 @param Global Pointer to VARAIBLE_GLOBAL structure.
232 @param Volatile Point out the Variable is Volatile or Non-Volatile.
233 @param SetByIndex TRUE if target pointer is given as index.
234 FALSE if target pointer is absolute.
235 @param Fvb Pointer to the writable FVB protocol.
236 @param DataPtrIndex Pointer to the Data from the end of VARIABLE_STORE_HEADER
238 @param DataSize Size of data to be written.
239 @param Buffer Pointer to the buffer from which data is written.
241 @retval EFI_INVALID_PARAMETER Parameters not valid.
242 @retval EFI_UNSUPPORTED Fvb is a NULL for Non-Volatile variable update.
243 @retval EFI_OUT_OF_RESOURCES The remaining size is not enough.
244 @retval EFI_SUCCESS Variable store successfully updated.
248 UpdateVariableStore (
249 IN VARIABLE_GLOBAL
*Global
,
251 IN BOOLEAN SetByIndex
,
252 IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*Fvb
,
253 IN UINTN DataPtrIndex
,
258 EFI_FV_BLOCK_MAP_ENTRY
*PtrBlockMapEntry
;
266 VARIABLE_STORE_HEADER
*VolatileBase
;
267 EFI_PHYSICAL_ADDRESS FvVolHdr
;
268 EFI_PHYSICAL_ADDRESS DataPtr
;
272 DataPtr
= DataPtrIndex
;
275 // Check if the Data is Volatile.
277 if (!Volatile
&& !mVariableModuleGlobal
->VariableGlobal
.EmuNvMode
) {
279 return EFI_UNSUPPORTED
;
281 Status
= Fvb
->GetPhysicalAddress(Fvb
, &FvVolHdr
);
282 ASSERT_EFI_ERROR (Status
);
285 // Data Pointer should point to the actual Address where data is to be
289 DataPtr
+= mVariableModuleGlobal
->VariableGlobal
.NonVolatileVariableBase
;
292 if ((DataPtr
+ DataSize
) > (FvVolHdr
+ mNvFvHeaderCache
->FvLength
)) {
293 return EFI_OUT_OF_RESOURCES
;
297 // Data Pointer should point to the actual Address where data is to be
301 VolatileBase
= (VARIABLE_STORE_HEADER
*) ((UINTN
) mVariableModuleGlobal
->VariableGlobal
.VolatileVariableBase
);
303 DataPtr
+= mVariableModuleGlobal
->VariableGlobal
.VolatileVariableBase
;
306 if ((DataPtr
+ DataSize
) > ((UINTN
) VolatileBase
+ VolatileBase
->Size
)) {
307 return EFI_OUT_OF_RESOURCES
;
311 // Emulated non-volatile variable mode.
314 DataPtr
+= (UINTN
) mNvVariableCache
;
317 if ((DataPtr
+ DataSize
) > ((UINTN
) mNvVariableCache
+ mNvVariableCache
->Size
)) {
318 return EFI_OUT_OF_RESOURCES
;
323 // If Volatile/Emulated Non-volatile Variable just do a simple mem copy.
325 CopyMem ((UINT8
*)(UINTN
)DataPtr
, Buffer
, DataSize
);
330 // If we are here we are dealing with Non-Volatile Variables.
332 LinearOffset
= (UINTN
) FvVolHdr
;
333 CurrWritePtr
= (UINTN
) DataPtr
;
334 CurrWriteSize
= DataSize
;
338 if (CurrWritePtr
< LinearOffset
) {
339 return EFI_INVALID_PARAMETER
;
342 for (PtrBlockMapEntry
= mNvFvHeaderCache
->BlockMap
; PtrBlockMapEntry
->NumBlocks
!= 0; PtrBlockMapEntry
++) {
343 for (BlockIndex2
= 0; BlockIndex2
< PtrBlockMapEntry
->NumBlocks
; BlockIndex2
++) {
345 // Check to see if the Variable Writes are spanning through multiple
348 if ((CurrWritePtr
>= LinearOffset
) && (CurrWritePtr
< LinearOffset
+ PtrBlockMapEntry
->Length
)) {
349 if ((CurrWritePtr
+ CurrWriteSize
) <= (LinearOffset
+ PtrBlockMapEntry
->Length
)) {
350 Status
= Fvb
->Write (
353 (UINTN
) (CurrWritePtr
- LinearOffset
),
359 Size
= (UINT32
) (LinearOffset
+ PtrBlockMapEntry
->Length
- CurrWritePtr
);
360 Status
= Fvb
->Write (
363 (UINTN
) (CurrWritePtr
- LinearOffset
),
367 if (EFI_ERROR (Status
)) {
371 CurrWritePtr
= LinearOffset
+ PtrBlockMapEntry
->Length
;
372 CurrBuffer
= CurrBuffer
+ Size
;
373 CurrWriteSize
= CurrWriteSize
- Size
;
377 LinearOffset
+= PtrBlockMapEntry
->Length
;
388 This code gets the current status of Variable Store.
390 @param VarStoreHeader Pointer to the Variable Store Header.
392 @retval EfiRaw Variable store status is raw.
393 @retval EfiValid Variable store status is valid.
394 @retval EfiInvalid Variable store status is invalid.
397 VARIABLE_STORE_STATUS
398 GetVariableStoreStatus (
399 IN VARIABLE_STORE_HEADER
*VarStoreHeader
402 if ((CompareGuid (&VarStoreHeader
->Signature
, &gEfiAuthenticatedVariableGuid
) ||
403 CompareGuid (&VarStoreHeader
->Signature
, &gEfiVariableGuid
)) &&
404 VarStoreHeader
->Format
== VARIABLE_STORE_FORMATTED
&&
405 VarStoreHeader
->State
== VARIABLE_STORE_HEALTHY
409 } else if (((UINT32
*)(&VarStoreHeader
->Signature
))[0] == 0xffffffff &&
410 ((UINT32
*)(&VarStoreHeader
->Signature
))[1] == 0xffffffff &&
411 ((UINT32
*)(&VarStoreHeader
->Signature
))[2] == 0xffffffff &&
412 ((UINT32
*)(&VarStoreHeader
->Signature
))[3] == 0xffffffff &&
413 VarStoreHeader
->Size
== 0xffffffff &&
414 VarStoreHeader
->Format
== 0xff &&
415 VarStoreHeader
->State
== 0xff
425 This code gets the size of variable header.
427 @return Size of variable header in bytes in type UINTN.
431 GetVariableHeaderSize (
437 if (mVariableModuleGlobal
->VariableGlobal
.AuthFormat
) {
438 Value
= sizeof (AUTHENTICATED_VARIABLE_HEADER
);
440 Value
= sizeof (VARIABLE_HEADER
);
448 This code gets the size of name of variable.
450 @param Variable Pointer to the Variable Header.
452 @return UINTN Size of variable in bytes.
457 IN VARIABLE_HEADER
*Variable
460 AUTHENTICATED_VARIABLE_HEADER
*AuthVariable
;
462 AuthVariable
= (AUTHENTICATED_VARIABLE_HEADER
*) Variable
;
463 if (mVariableModuleGlobal
->VariableGlobal
.AuthFormat
) {
464 if (AuthVariable
->State
== (UINT8
) (-1) ||
465 AuthVariable
->DataSize
== (UINT32
) (-1) ||
466 AuthVariable
->NameSize
== (UINT32
) (-1) ||
467 AuthVariable
->Attributes
== (UINT32
) (-1)) {
470 return (UINTN
) AuthVariable
->NameSize
;
472 if (Variable
->State
== (UINT8
) (-1) ||
473 Variable
->DataSize
== (UINT32
) (-1) ||
474 Variable
->NameSize
== (UINT32
) (-1) ||
475 Variable
->Attributes
== (UINT32
) (-1)) {
478 return (UINTN
) Variable
->NameSize
;
483 This code sets the size of name of variable.
485 @param[in] Variable Pointer to the Variable Header.
486 @param[in] NameSize Name size to set.
490 SetNameSizeOfVariable (
491 IN VARIABLE_HEADER
*Variable
,
495 AUTHENTICATED_VARIABLE_HEADER
*AuthVariable
;
497 AuthVariable
= (AUTHENTICATED_VARIABLE_HEADER
*) Variable
;
498 if (mVariableModuleGlobal
->VariableGlobal
.AuthFormat
) {
499 AuthVariable
->NameSize
= (UINT32
) NameSize
;
501 Variable
->NameSize
= (UINT32
) NameSize
;
507 This code gets the size of variable data.
509 @param Variable Pointer to the Variable Header.
511 @return Size of variable in bytes.
516 IN VARIABLE_HEADER
*Variable
519 AUTHENTICATED_VARIABLE_HEADER
*AuthVariable
;
521 AuthVariable
= (AUTHENTICATED_VARIABLE_HEADER
*) Variable
;
522 if (mVariableModuleGlobal
->VariableGlobal
.AuthFormat
) {
523 if (AuthVariable
->State
== (UINT8
) (-1) ||
524 AuthVariable
->DataSize
== (UINT32
) (-1) ||
525 AuthVariable
->NameSize
== (UINT32
) (-1) ||
526 AuthVariable
->Attributes
== (UINT32
) (-1)) {
529 return (UINTN
) AuthVariable
->DataSize
;
531 if (Variable
->State
== (UINT8
) (-1) ||
532 Variable
->DataSize
== (UINT32
) (-1) ||
533 Variable
->NameSize
== (UINT32
) (-1) ||
534 Variable
->Attributes
== (UINT32
) (-1)) {
537 return (UINTN
) Variable
->DataSize
;
542 This code sets the size of variable data.
544 @param[in] Variable Pointer to the Variable Header.
545 @param[in] DataSize Data size to set.
549 SetDataSizeOfVariable (
550 IN VARIABLE_HEADER
*Variable
,
554 AUTHENTICATED_VARIABLE_HEADER
*AuthVariable
;
556 AuthVariable
= (AUTHENTICATED_VARIABLE_HEADER
*) Variable
;
557 if (mVariableModuleGlobal
->VariableGlobal
.AuthFormat
) {
558 AuthVariable
->DataSize
= (UINT32
) DataSize
;
560 Variable
->DataSize
= (UINT32
) DataSize
;
566 This code gets the pointer to the variable name.
568 @param Variable Pointer to the Variable Header.
570 @return Pointer to Variable Name which is Unicode encoding.
575 IN VARIABLE_HEADER
*Variable
578 return (CHAR16
*) ((UINTN
) Variable
+ GetVariableHeaderSize ());
582 This code gets the pointer to the variable guid.
584 @param Variable Pointer to the Variable Header.
586 @return A EFI_GUID* pointer to Vendor Guid.
591 IN VARIABLE_HEADER
*Variable
594 AUTHENTICATED_VARIABLE_HEADER
*AuthVariable
;
596 AuthVariable
= (AUTHENTICATED_VARIABLE_HEADER
*) Variable
;
597 if (mVariableModuleGlobal
->VariableGlobal
.AuthFormat
) {
598 return &AuthVariable
->VendorGuid
;
600 return &Variable
->VendorGuid
;
606 This code gets the pointer to the variable data.
608 @param Variable Pointer to the Variable Header.
610 @return Pointer to Variable Data.
615 IN VARIABLE_HEADER
*Variable
621 // Be careful about pad size for alignment.
623 Value
= (UINTN
) GetVariableNamePtr (Variable
);
624 Value
+= NameSizeOfVariable (Variable
);
625 Value
+= GET_PAD_SIZE (NameSizeOfVariable (Variable
));
627 return (UINT8
*) Value
;
631 This code gets the variable data offset related to variable header.
633 @param Variable Pointer to the Variable Header.
635 @return Variable Data offset.
639 GetVariableDataOffset (
640 IN VARIABLE_HEADER
*Variable
646 // Be careful about pad size for alignment
648 Value
= GetVariableHeaderSize ();
649 Value
+= NameSizeOfVariable (Variable
);
650 Value
+= GET_PAD_SIZE (NameSizeOfVariable (Variable
));
657 This code gets the pointer to the next variable header.
659 @param Variable Pointer to the Variable Header.
661 @return Pointer to next variable header.
666 IN VARIABLE_HEADER
*Variable
671 Value
= (UINTN
) GetVariableDataPtr (Variable
);
672 Value
+= DataSizeOfVariable (Variable
);
673 Value
+= GET_PAD_SIZE (DataSizeOfVariable (Variable
));
676 // Be careful about pad size for alignment.
678 return (VARIABLE_HEADER
*) HEADER_ALIGN (Value
);
683 Gets the pointer to the first variable header in given variable store area.
685 @param VarStoreHeader Pointer to the Variable Store Header.
687 @return Pointer to the first variable header.
692 IN VARIABLE_STORE_HEADER
*VarStoreHeader
696 // The start of variable store.
698 return (VARIABLE_HEADER
*) HEADER_ALIGN (VarStoreHeader
+ 1);
703 Gets the pointer to the end of the variable storage area.
705 This function gets pointer to the end of the variable storage
706 area, according to the input variable store header.
708 @param VarStoreHeader Pointer to the Variable Store Header.
710 @return Pointer to the end of the variable storage area.
715 IN VARIABLE_STORE_HEADER
*VarStoreHeader
719 // The end of variable store
721 return (VARIABLE_HEADER
*) HEADER_ALIGN ((UINTN
) VarStoreHeader
+ VarStoreHeader
->Size
);
725 Record variable error flag.
727 @param[in] Flag Variable error flag to record.
728 @param[in] VariableName Name of variable.
729 @param[in] VendorGuid Guid of variable.
730 @param[in] Attributes Attributes of the variable.
731 @param[in] VariableSize Size of the variable.
736 IN VAR_ERROR_FLAG Flag
,
737 IN CHAR16
*VariableName
,
738 IN EFI_GUID
*VendorGuid
,
739 IN UINT32 Attributes
,
740 IN UINTN VariableSize
744 VARIABLE_POINTER_TRACK Variable
;
745 VAR_ERROR_FLAG
*VarErrFlag
;
746 VAR_ERROR_FLAG TempFlag
;
749 DEBUG ((EFI_D_ERROR
, "RecordVarErrorFlag (0x%02x) %s:%g - 0x%08x - 0x%x\n", Flag
, VariableName
, VendorGuid
, Attributes
, VariableSize
));
750 if (Flag
== VAR_ERROR_FLAG_SYSTEM_ERROR
) {
752 DEBUG ((EFI_D_ERROR
, "CommonRuntimeVariableSpace = 0x%x - CommonVariableTotalSize = 0x%x\n", mVariableModuleGlobal
->CommonRuntimeVariableSpace
, mVariableModuleGlobal
->CommonVariableTotalSize
));
754 DEBUG ((EFI_D_ERROR
, "CommonVariableSpace = 0x%x - CommonVariableTotalSize = 0x%x\n", mVariableModuleGlobal
->CommonVariableSpace
, mVariableModuleGlobal
->CommonVariableTotalSize
));
757 DEBUG ((EFI_D_ERROR
, "CommonMaxUserVariableSpace = 0x%x - CommonUserVariableTotalSize = 0x%x\n", mVariableModuleGlobal
->CommonMaxUserVariableSpace
, mVariableModuleGlobal
->CommonUserVariableTotalSize
));
763 // Before EndOfDxe, just record the current boot variable error flag to local variable,
764 // and leave the variable error flag in NV flash as the last boot variable error flag.
765 // After EndOfDxe in InitializeVarErrorFlag (), the variable error flag in NV flash
766 // will be initialized to this local current boot variable error flag.
768 mCurrentBootVarErrFlag
&= Flag
;
773 // Record error flag (it should have be initialized).
775 Status
= FindVariable (
777 &gEdkiiVarErrorFlagGuid
,
779 &mVariableModuleGlobal
->VariableGlobal
,
782 if (!EFI_ERROR (Status
)) {
783 VarErrFlag
= (VAR_ERROR_FLAG
*) GetVariableDataPtr (Variable
.CurrPtr
);
784 TempFlag
= *VarErrFlag
;
786 if (TempFlag
== *VarErrFlag
) {
789 Status
= UpdateVariableStore (
790 &mVariableModuleGlobal
->VariableGlobal
,
793 mVariableModuleGlobal
->FvbInstance
,
794 (UINTN
) VarErrFlag
- (UINTN
) mNvVariableCache
+ (UINTN
) mVariableModuleGlobal
->VariableGlobal
.NonVolatileVariableBase
,
798 if (!EFI_ERROR (Status
)) {
800 // Update the data in NV cache.
802 *VarErrFlag
= TempFlag
;
808 Initialize variable error flag.
810 Before EndOfDxe, the variable indicates the last boot variable error flag,
811 then it means the last boot variable error flag must be got before EndOfDxe.
812 After EndOfDxe, the variable indicates the current boot variable error flag,
813 then it means the current boot variable error flag must be got after EndOfDxe.
817 InitializeVarErrorFlag (
822 VARIABLE_POINTER_TRACK Variable
;
824 VAR_ERROR_FLAG VarErrFlag
;
830 Flag
= mCurrentBootVarErrFlag
;
831 DEBUG ((EFI_D_INFO
, "Initialize variable error flag (%02x)\n", Flag
));
833 Status
= FindVariable (
835 &gEdkiiVarErrorFlagGuid
,
837 &mVariableModuleGlobal
->VariableGlobal
,
840 if (!EFI_ERROR (Status
)) {
841 VarErrFlag
= *((VAR_ERROR_FLAG
*) GetVariableDataPtr (Variable
.CurrPtr
));
842 if (VarErrFlag
== Flag
) {
849 &gEdkiiVarErrorFlagGuid
,
852 VARIABLE_ATTRIBUTE_NV_BS_RT
,
863 @param[in] Variable Pointer to variable header.
865 @retval TRUE User variable.
866 @retval FALSE System variable.
871 IN VARIABLE_HEADER
*Variable
874 VAR_CHECK_VARIABLE_PROPERTY Property
;
877 // Only after End Of Dxe, the variables belong to system variable are fixed.
878 // If PcdMaxUserNvStorageVariableSize is 0, it means user variable share the same NV storage with system variable,
879 // then no need to check if the variable is user variable or not specially.
881 if (mEndOfDxe
&& (mVariableModuleGlobal
->CommonMaxUserVariableSpace
!= mVariableModuleGlobal
->CommonVariableSpace
)) {
882 if (VarCheckLibVariablePropertyGet (GetVariableNamePtr (Variable
), GetVendorGuidPtr (Variable
), &Property
) == EFI_NOT_FOUND
) {
890 Calculate common user variable total size.
894 CalculateCommonUserVariableTotalSize (
898 VARIABLE_HEADER
*Variable
;
899 VARIABLE_HEADER
*NextVariable
;
901 VAR_CHECK_VARIABLE_PROPERTY Property
;
904 // Only after End Of Dxe, the variables belong to system variable are fixed.
905 // If PcdMaxUserNvStorageVariableSize is 0, it means user variable share the same NV storage with system variable,
906 // then no need to calculate the common user variable total size specially.
908 if (mEndOfDxe
&& (mVariableModuleGlobal
->CommonMaxUserVariableSpace
!= mVariableModuleGlobal
->CommonVariableSpace
)) {
909 Variable
= GetStartPointer (mNvVariableCache
);
910 while (IsValidVariableHeader (Variable
, GetEndPointer (mNvVariableCache
))) {
911 NextVariable
= GetNextVariablePtr (Variable
);
912 VariableSize
= (UINTN
) NextVariable
- (UINTN
) Variable
;
913 if ((Variable
->Attributes
& EFI_VARIABLE_HARDWARE_ERROR_RECORD
) != EFI_VARIABLE_HARDWARE_ERROR_RECORD
) {
914 if (VarCheckLibVariablePropertyGet (GetVariableNamePtr (Variable
), GetVendorGuidPtr (Variable
), &Property
) == EFI_NOT_FOUND
) {
916 // No property, it is user variable.
918 mVariableModuleGlobal
->CommonUserVariableTotalSize
+= VariableSize
;
922 Variable
= NextVariable
;
928 Initialize variable quota.
932 InitializeVariableQuota (
940 InitializeVarErrorFlag ();
941 CalculateCommonUserVariableTotalSize ();
946 Variable store garbage collection and reclaim operation.
948 @param[in] VariableBase Base address of variable store.
949 @param[out] LastVariableOffset Offset of last variable.
950 @param[in] IsVolatile The variable store is volatile or not;
951 if it is non-volatile, need FTW.
952 @param[in, out] UpdatingPtrTrack Pointer to updating variable pointer track structure.
953 @param[in] NewVariable Pointer to new variable.
954 @param[in] NewVariableSize New variable size.
956 @return EFI_SUCCESS Reclaim operation has finished successfully.
957 @return EFI_OUT_OF_RESOURCES No enough memory resources or variable space.
958 @return Others Unexpect error happened during reclaim operation.
963 IN EFI_PHYSICAL_ADDRESS VariableBase
,
964 OUT UINTN
*LastVariableOffset
,
965 IN BOOLEAN IsVolatile
,
966 IN OUT VARIABLE_POINTER_TRACK
*UpdatingPtrTrack
,
967 IN VARIABLE_HEADER
*NewVariable
,
968 IN UINTN NewVariableSize
971 VARIABLE_HEADER
*Variable
;
972 VARIABLE_HEADER
*AddedVariable
;
973 VARIABLE_HEADER
*NextVariable
;
974 VARIABLE_HEADER
*NextAddedVariable
;
975 VARIABLE_STORE_HEADER
*VariableStoreHeader
;
977 UINTN MaximumBufferSize
;
985 UINTN CommonVariableTotalSize
;
986 UINTN CommonUserVariableTotalSize
;
987 UINTN HwErrVariableTotalSize
;
988 VARIABLE_HEADER
*UpdatingVariable
;
989 VARIABLE_HEADER
*UpdatingInDeletedTransition
;
991 UpdatingVariable
= NULL
;
992 UpdatingInDeletedTransition
= NULL
;
993 if (UpdatingPtrTrack
!= NULL
) {
994 UpdatingVariable
= UpdatingPtrTrack
->CurrPtr
;
995 UpdatingInDeletedTransition
= UpdatingPtrTrack
->InDeletedTransitionPtr
;
998 VariableStoreHeader
= (VARIABLE_STORE_HEADER
*) ((UINTN
) VariableBase
);
1000 CommonVariableTotalSize
= 0;
1001 CommonUserVariableTotalSize
= 0;
1002 HwErrVariableTotalSize
= 0;
1004 if (IsVolatile
|| mVariableModuleGlobal
->VariableGlobal
.EmuNvMode
) {
1006 // Start Pointers for the variable.
1008 Variable
= GetStartPointer (VariableStoreHeader
);
1009 MaximumBufferSize
= sizeof (VARIABLE_STORE_HEADER
);
1011 while (IsValidVariableHeader (Variable
, GetEndPointer (VariableStoreHeader
))) {
1012 NextVariable
= GetNextVariablePtr (Variable
);
1013 if ((Variable
->State
== VAR_ADDED
|| Variable
->State
== (VAR_IN_DELETED_TRANSITION
& VAR_ADDED
)) &&
1014 Variable
!= UpdatingVariable
&&
1015 Variable
!= UpdatingInDeletedTransition
1017 VariableSize
= (UINTN
) NextVariable
- (UINTN
) Variable
;
1018 MaximumBufferSize
+= VariableSize
;
1021 Variable
= NextVariable
;
1024 if (NewVariable
!= NULL
) {
1026 // Add the new variable size.
1028 MaximumBufferSize
+= NewVariableSize
;
1032 // Reserve the 1 Bytes with Oxff to identify the
1033 // end of the variable buffer.
1035 MaximumBufferSize
+= 1;
1036 ValidBuffer
= AllocatePool (MaximumBufferSize
);
1037 if (ValidBuffer
== NULL
) {
1038 return EFI_OUT_OF_RESOURCES
;
1042 // For NV variable reclaim, don't allocate pool here and just use mNvVariableCache
1043 // as the buffer to reduce SMRAM consumption for SMM variable driver.
1045 MaximumBufferSize
= mNvVariableCache
->Size
;
1046 ValidBuffer
= (UINT8
*) mNvVariableCache
;
1049 SetMem (ValidBuffer
, MaximumBufferSize
, 0xff);
1052 // Copy variable store header.
1054 CopyMem (ValidBuffer
, VariableStoreHeader
, sizeof (VARIABLE_STORE_HEADER
));
1055 CurrPtr
= (UINT8
*) GetStartPointer ((VARIABLE_STORE_HEADER
*) ValidBuffer
);
1058 // Reinstall all ADDED variables as long as they are not identical to Updating Variable.
1060 Variable
= GetStartPointer (VariableStoreHeader
);
1061 while (IsValidVariableHeader (Variable
, GetEndPointer (VariableStoreHeader
))) {
1062 NextVariable
= GetNextVariablePtr (Variable
);
1063 if (Variable
!= UpdatingVariable
&& Variable
->State
== VAR_ADDED
) {
1064 VariableSize
= (UINTN
) NextVariable
- (UINTN
) Variable
;
1065 CopyMem (CurrPtr
, (UINT8
*) Variable
, VariableSize
);
1066 CurrPtr
+= VariableSize
;
1067 if ((!IsVolatile
) && ((Variable
->Attributes
& EFI_VARIABLE_HARDWARE_ERROR_RECORD
) == EFI_VARIABLE_HARDWARE_ERROR_RECORD
)) {
1068 HwErrVariableTotalSize
+= VariableSize
;
1069 } else if ((!IsVolatile
) && ((Variable
->Attributes
& EFI_VARIABLE_HARDWARE_ERROR_RECORD
) != EFI_VARIABLE_HARDWARE_ERROR_RECORD
)) {
1070 CommonVariableTotalSize
+= VariableSize
;
1071 if (IsUserVariable (Variable
)) {
1072 CommonUserVariableTotalSize
+= VariableSize
;
1076 Variable
= NextVariable
;
1080 // Reinstall all in delete transition variables.
1082 Variable
= GetStartPointer (VariableStoreHeader
);
1083 while (IsValidVariableHeader (Variable
, GetEndPointer (VariableStoreHeader
))) {
1084 NextVariable
= GetNextVariablePtr (Variable
);
1085 if (Variable
!= UpdatingVariable
&& Variable
!= UpdatingInDeletedTransition
&& Variable
->State
== (VAR_IN_DELETED_TRANSITION
& VAR_ADDED
)) {
1088 // Buffer has cached all ADDED variable.
1089 // Per IN_DELETED variable, we have to guarantee that
1090 // no ADDED one in previous buffer.
1094 AddedVariable
= GetStartPointer ((VARIABLE_STORE_HEADER
*) ValidBuffer
);
1095 while (IsValidVariableHeader (AddedVariable
, GetEndPointer ((VARIABLE_STORE_HEADER
*) ValidBuffer
))) {
1096 NextAddedVariable
= GetNextVariablePtr (AddedVariable
);
1097 NameSize
= NameSizeOfVariable (AddedVariable
);
1098 if (CompareGuid (GetVendorGuidPtr (AddedVariable
), GetVendorGuidPtr (Variable
)) &&
1099 NameSize
== NameSizeOfVariable (Variable
)
1101 Point0
= (VOID
*) GetVariableNamePtr (AddedVariable
);
1102 Point1
= (VOID
*) GetVariableNamePtr (Variable
);
1103 if (CompareMem (Point0
, Point1
, NameSize
) == 0) {
1108 AddedVariable
= NextAddedVariable
;
1112 // Promote VAR_IN_DELETED_TRANSITION to VAR_ADDED.
1114 VariableSize
= (UINTN
) NextVariable
- (UINTN
) Variable
;
1115 CopyMem (CurrPtr
, (UINT8
*) Variable
, VariableSize
);
1116 ((VARIABLE_HEADER
*) CurrPtr
)->State
= VAR_ADDED
;
1117 CurrPtr
+= VariableSize
;
1118 if ((!IsVolatile
) && ((Variable
->Attributes
& EFI_VARIABLE_HARDWARE_ERROR_RECORD
) == EFI_VARIABLE_HARDWARE_ERROR_RECORD
)) {
1119 HwErrVariableTotalSize
+= VariableSize
;
1120 } else if ((!IsVolatile
) && ((Variable
->Attributes
& EFI_VARIABLE_HARDWARE_ERROR_RECORD
) != EFI_VARIABLE_HARDWARE_ERROR_RECORD
)) {
1121 CommonVariableTotalSize
+= VariableSize
;
1122 if (IsUserVariable (Variable
)) {
1123 CommonUserVariableTotalSize
+= VariableSize
;
1129 Variable
= NextVariable
;
1133 // Install the new variable if it is not NULL.
1135 if (NewVariable
!= NULL
) {
1136 if (((UINTN
) CurrPtr
- (UINTN
) ValidBuffer
) + NewVariableSize
> VariableStoreHeader
->Size
) {
1138 // No enough space to store the new variable.
1140 Status
= EFI_OUT_OF_RESOURCES
;
1144 if ((NewVariable
->Attributes
& EFI_VARIABLE_HARDWARE_ERROR_RECORD
) == EFI_VARIABLE_HARDWARE_ERROR_RECORD
) {
1145 HwErrVariableTotalSize
+= NewVariableSize
;
1146 } else if ((NewVariable
->Attributes
& EFI_VARIABLE_HARDWARE_ERROR_RECORD
) != EFI_VARIABLE_HARDWARE_ERROR_RECORD
) {
1147 CommonVariableTotalSize
+= NewVariableSize
;
1148 if (IsUserVariable (NewVariable
)) {
1149 CommonUserVariableTotalSize
+= NewVariableSize
;
1152 if ((HwErrVariableTotalSize
> PcdGet32 (PcdHwErrStorageSize
)) ||
1153 (CommonVariableTotalSize
> mVariableModuleGlobal
->CommonVariableSpace
) ||
1154 (CommonUserVariableTotalSize
> mVariableModuleGlobal
->CommonMaxUserVariableSpace
)) {
1156 // No enough space to store the new variable by NV or NV+HR attribute.
1158 Status
= EFI_OUT_OF_RESOURCES
;
1163 CopyMem (CurrPtr
, (UINT8
*) NewVariable
, NewVariableSize
);
1164 ((VARIABLE_HEADER
*) CurrPtr
)->State
= VAR_ADDED
;
1165 if (UpdatingVariable
!= NULL
) {
1166 UpdatingPtrTrack
->CurrPtr
= (VARIABLE_HEADER
*)((UINTN
)UpdatingPtrTrack
->StartPtr
+ ((UINTN
)CurrPtr
- (UINTN
)GetStartPointer ((VARIABLE_STORE_HEADER
*) ValidBuffer
)));
1167 UpdatingPtrTrack
->InDeletedTransitionPtr
= NULL
;
1169 CurrPtr
+= NewVariableSize
;
1172 if (IsVolatile
|| mVariableModuleGlobal
->VariableGlobal
.EmuNvMode
) {
1174 // If volatile/emulated non-volatile variable store, just copy valid buffer.
1176 SetMem ((UINT8
*) (UINTN
) VariableBase
, VariableStoreHeader
->Size
, 0xff);
1177 CopyMem ((UINT8
*) (UINTN
) VariableBase
, ValidBuffer
, (UINTN
) CurrPtr
- (UINTN
) ValidBuffer
);
1178 *LastVariableOffset
= (UINTN
) CurrPtr
- (UINTN
) ValidBuffer
;
1181 // Emulated non-volatile variable mode.
1183 mVariableModuleGlobal
->HwErrVariableTotalSize
= HwErrVariableTotalSize
;
1184 mVariableModuleGlobal
->CommonVariableTotalSize
= CommonVariableTotalSize
;
1185 mVariableModuleGlobal
->CommonUserVariableTotalSize
= CommonUserVariableTotalSize
;
1187 Status
= EFI_SUCCESS
;
1190 // If non-volatile variable store, perform FTW here.
1192 Status
= FtwVariableSpace (
1194 (VARIABLE_STORE_HEADER
*) ValidBuffer
1196 if (!EFI_ERROR (Status
)) {
1197 *LastVariableOffset
= (UINTN
) CurrPtr
- (UINTN
) ValidBuffer
;
1198 mVariableModuleGlobal
->HwErrVariableTotalSize
= HwErrVariableTotalSize
;
1199 mVariableModuleGlobal
->CommonVariableTotalSize
= CommonVariableTotalSize
;
1200 mVariableModuleGlobal
->CommonUserVariableTotalSize
= CommonUserVariableTotalSize
;
1202 mVariableModuleGlobal
->HwErrVariableTotalSize
= 0;
1203 mVariableModuleGlobal
->CommonVariableTotalSize
= 0;
1204 mVariableModuleGlobal
->CommonUserVariableTotalSize
= 0;
1205 Variable
= GetStartPointer ((VARIABLE_STORE_HEADER
*)(UINTN
)VariableBase
);
1206 while (IsValidVariableHeader (Variable
, GetEndPointer ((VARIABLE_STORE_HEADER
*)(UINTN
)VariableBase
))) {
1207 NextVariable
= GetNextVariablePtr (Variable
);
1208 VariableSize
= (UINTN
) NextVariable
- (UINTN
) Variable
;
1209 if ((Variable
->Attributes
& EFI_VARIABLE_HARDWARE_ERROR_RECORD
) == EFI_VARIABLE_HARDWARE_ERROR_RECORD
) {
1210 mVariableModuleGlobal
->HwErrVariableTotalSize
+= VariableSize
;
1211 } else if ((Variable
->Attributes
& EFI_VARIABLE_HARDWARE_ERROR_RECORD
) != EFI_VARIABLE_HARDWARE_ERROR_RECORD
) {
1212 mVariableModuleGlobal
->CommonVariableTotalSize
+= VariableSize
;
1213 if (IsUserVariable (Variable
)) {
1214 mVariableModuleGlobal
->CommonUserVariableTotalSize
+= VariableSize
;
1218 Variable
= NextVariable
;
1220 *LastVariableOffset
= (UINTN
) Variable
- (UINTN
) VariableBase
;
1225 if (IsVolatile
|| mVariableModuleGlobal
->VariableGlobal
.EmuNvMode
) {
1226 FreePool (ValidBuffer
);
1229 // For NV variable reclaim, we use mNvVariableCache as the buffer, so copy the data back.
1231 CopyMem (mNvVariableCache
, (UINT8
*)(UINTN
)VariableBase
, VariableStoreHeader
->Size
);
1238 Find the variable in the specified variable store.
1240 @param[in] VariableName Name of the variable to be found
1241 @param[in] VendorGuid Vendor GUID to be found.
1242 @param[in] IgnoreRtCheck Ignore EFI_VARIABLE_RUNTIME_ACCESS attribute
1243 check at runtime when searching variable.
1244 @param[in, out] PtrTrack Variable Track Pointer structure that contains Variable Information.
1246 @retval EFI_SUCCESS Variable found successfully
1247 @retval EFI_NOT_FOUND Variable not found
1251 IN CHAR16
*VariableName
,
1252 IN EFI_GUID
*VendorGuid
,
1253 IN BOOLEAN IgnoreRtCheck
,
1254 IN OUT VARIABLE_POINTER_TRACK
*PtrTrack
1257 VARIABLE_HEADER
*InDeletedVariable
;
1260 PtrTrack
->InDeletedTransitionPtr
= NULL
;
1263 // Find the variable by walk through HOB, volatile and non-volatile variable store.
1265 InDeletedVariable
= NULL
;
1267 for ( PtrTrack
->CurrPtr
= PtrTrack
->StartPtr
1268 ; IsValidVariableHeader (PtrTrack
->CurrPtr
, PtrTrack
->EndPtr
)
1269 ; PtrTrack
->CurrPtr
= GetNextVariablePtr (PtrTrack
->CurrPtr
)
1271 if (PtrTrack
->CurrPtr
->State
== VAR_ADDED
||
1272 PtrTrack
->CurrPtr
->State
== (VAR_IN_DELETED_TRANSITION
& VAR_ADDED
)
1274 if (IgnoreRtCheck
|| !AtRuntime () || ((PtrTrack
->CurrPtr
->Attributes
& EFI_VARIABLE_RUNTIME_ACCESS
) != 0)) {
1275 if (VariableName
[0] == 0) {
1276 if (PtrTrack
->CurrPtr
->State
== (VAR_IN_DELETED_TRANSITION
& VAR_ADDED
)) {
1277 InDeletedVariable
= PtrTrack
->CurrPtr
;
1279 PtrTrack
->InDeletedTransitionPtr
= InDeletedVariable
;
1283 if (CompareGuid (VendorGuid
, GetVendorGuidPtr (PtrTrack
->CurrPtr
))) {
1284 Point
= (VOID
*) GetVariableNamePtr (PtrTrack
->CurrPtr
);
1286 ASSERT (NameSizeOfVariable (PtrTrack
->CurrPtr
) != 0);
1287 if (CompareMem (VariableName
, Point
, NameSizeOfVariable (PtrTrack
->CurrPtr
)) == 0) {
1288 if (PtrTrack
->CurrPtr
->State
== (VAR_IN_DELETED_TRANSITION
& VAR_ADDED
)) {
1289 InDeletedVariable
= PtrTrack
->CurrPtr
;
1291 PtrTrack
->InDeletedTransitionPtr
= InDeletedVariable
;
1301 PtrTrack
->CurrPtr
= InDeletedVariable
;
1302 return (PtrTrack
->CurrPtr
== NULL
) ? EFI_NOT_FOUND
: EFI_SUCCESS
;
1307 Finds variable in storage blocks of volatile and non-volatile storage areas.
1309 This code finds variable in storage blocks of volatile and non-volatile storage areas.
1310 If VariableName is an empty string, then we just return the first
1311 qualified variable without comparing VariableName and VendorGuid.
1312 If IgnoreRtCheck is TRUE, then we ignore the EFI_VARIABLE_RUNTIME_ACCESS attribute check
1313 at runtime when searching existing variable, only VariableName and VendorGuid are compared.
1314 Otherwise, variables without EFI_VARIABLE_RUNTIME_ACCESS are not visible at runtime.
1316 @param[in] VariableName Name of the variable to be found.
1317 @param[in] VendorGuid Vendor GUID to be found.
1318 @param[out] PtrTrack VARIABLE_POINTER_TRACK structure for output,
1319 including the range searched and the target position.
1320 @param[in] Global Pointer to VARIABLE_GLOBAL structure, including
1321 base of volatile variable storage area, base of
1322 NV variable storage area, and a lock.
1323 @param[in] IgnoreRtCheck Ignore EFI_VARIABLE_RUNTIME_ACCESS attribute
1324 check at runtime when searching variable.
1326 @retval EFI_INVALID_PARAMETER If VariableName is not an empty string, while
1328 @retval EFI_SUCCESS Variable successfully found.
1329 @retval EFI_NOT_FOUND Variable not found
1334 IN CHAR16
*VariableName
,
1335 IN EFI_GUID
*VendorGuid
,
1336 OUT VARIABLE_POINTER_TRACK
*PtrTrack
,
1337 IN VARIABLE_GLOBAL
*Global
,
1338 IN BOOLEAN IgnoreRtCheck
1342 VARIABLE_STORE_HEADER
*VariableStoreHeader
[VariableStoreTypeMax
];
1343 VARIABLE_STORE_TYPE Type
;
1345 if (VariableName
[0] != 0 && VendorGuid
== NULL
) {
1346 return EFI_INVALID_PARAMETER
;
1350 // 0: Volatile, 1: HOB, 2: Non-Volatile.
1351 // The index and attributes mapping must be kept in this order as RuntimeServiceGetNextVariableName
1352 // make use of this mapping to implement search algorithm.
1354 VariableStoreHeader
[VariableStoreTypeVolatile
] = (VARIABLE_STORE_HEADER
*) (UINTN
) Global
->VolatileVariableBase
;
1355 VariableStoreHeader
[VariableStoreTypeHob
] = (VARIABLE_STORE_HEADER
*) (UINTN
) Global
->HobVariableBase
;
1356 VariableStoreHeader
[VariableStoreTypeNv
] = mNvVariableCache
;
1359 // Find the variable by walk through HOB, volatile and non-volatile variable store.
1361 for (Type
= (VARIABLE_STORE_TYPE
) 0; Type
< VariableStoreTypeMax
; Type
++) {
1362 if (VariableStoreHeader
[Type
] == NULL
) {
1366 PtrTrack
->StartPtr
= GetStartPointer (VariableStoreHeader
[Type
]);
1367 PtrTrack
->EndPtr
= GetEndPointer (VariableStoreHeader
[Type
]);
1368 PtrTrack
->Volatile
= (BOOLEAN
) (Type
== VariableStoreTypeVolatile
);
1370 Status
= FindVariableEx (VariableName
, VendorGuid
, IgnoreRtCheck
, PtrTrack
);
1371 if (!EFI_ERROR (Status
)) {
1375 return EFI_NOT_FOUND
;
1379 Get index from supported language codes according to language string.
1381 This code is used to get corresponding index in supported language codes. It can handle
1382 RFC4646 and ISO639 language tags.
1383 In ISO639 language tags, take 3-characters as a delimitation to find matched string and calculate the index.
1384 In RFC4646 language tags, take semicolon as a delimitation to find matched string and calculate the index.
1387 SupportedLang = "engfraengfra"
1389 Iso639Language = TRUE
1390 The return value is "0".
1392 SupportedLang = "en;fr;en-US;fr-FR"
1394 Iso639Language = FALSE
1395 The return value is "3".
1397 @param SupportedLang Platform supported language codes.
1398 @param Lang Configured language.
1399 @param Iso639Language A bool value to signify if the handler is operated on ISO639 or RFC4646.
1401 @retval The index of language in the language codes.
1405 GetIndexFromSupportedLangCodes(
1406 IN CHAR8
*SupportedLang
,
1408 IN BOOLEAN Iso639Language
1412 UINTN CompareLength
;
1413 UINTN LanguageLength
;
1415 if (Iso639Language
) {
1416 CompareLength
= ISO_639_2_ENTRY_SIZE
;
1417 for (Index
= 0; Index
< AsciiStrLen (SupportedLang
); Index
+= CompareLength
) {
1418 if (AsciiStrnCmp (Lang
, SupportedLang
+ Index
, CompareLength
) == 0) {
1420 // Successfully find the index of Lang string in SupportedLang string.
1422 Index
= Index
/ CompareLength
;
1430 // Compare RFC4646 language code
1433 for (LanguageLength
= 0; Lang
[LanguageLength
] != '\0'; LanguageLength
++);
1435 for (Index
= 0; *SupportedLang
!= '\0'; Index
++, SupportedLang
+= CompareLength
) {
1437 // Skip ';' characters in SupportedLang
1439 for (; *SupportedLang
!= '\0' && *SupportedLang
== ';'; SupportedLang
++);
1441 // Determine the length of the next language code in SupportedLang
1443 for (CompareLength
= 0; SupportedLang
[CompareLength
] != '\0' && SupportedLang
[CompareLength
] != ';'; CompareLength
++);
1445 if ((CompareLength
== LanguageLength
) &&
1446 (AsciiStrnCmp (Lang
, SupportedLang
, CompareLength
) == 0)) {
1448 // Successfully find the index of Lang string in SupportedLang string.
1459 Get language string from supported language codes according to index.
1461 This code is used to get corresponding language strings in supported language codes. It can handle
1462 RFC4646 and ISO639 language tags.
1463 In ISO639 language tags, take 3-characters as a delimitation. Find language string according to the index.
1464 In RFC4646 language tags, take semicolon as a delimitation. Find language string according to the index.
1467 SupportedLang = "engfraengfra"
1469 Iso639Language = TRUE
1470 The return value is "fra".
1472 SupportedLang = "en;fr;en-US;fr-FR"
1474 Iso639Language = FALSE
1475 The return value is "fr".
1477 @param SupportedLang Platform supported language codes.
1478 @param Index The index in supported language codes.
1479 @param Iso639Language A bool value to signify if the handler is operated on ISO639 or RFC4646.
1481 @retval The language string in the language codes.
1485 GetLangFromSupportedLangCodes (
1486 IN CHAR8
*SupportedLang
,
1488 IN BOOLEAN Iso639Language
1492 UINTN CompareLength
;
1496 Supported
= SupportedLang
;
1497 if (Iso639Language
) {
1499 // According to the index of Lang string in SupportedLang string to get the language.
1500 // This code will be invoked in RUNTIME, therefore there is not a memory allocate/free operation.
1501 // In driver entry, it pre-allocates a runtime attribute memory to accommodate this string.
1503 CompareLength
= ISO_639_2_ENTRY_SIZE
;
1504 mVariableModuleGlobal
->Lang
[CompareLength
] = '\0';
1505 return CopyMem (mVariableModuleGlobal
->Lang
, SupportedLang
+ Index
* CompareLength
, CompareLength
);
1510 // Take semicolon as delimitation, sequentially traverse supported language codes.
1512 for (CompareLength
= 0; *Supported
!= ';' && *Supported
!= '\0'; CompareLength
++) {
1515 if ((*Supported
== '\0') && (SubIndex
!= Index
)) {
1517 // Have completed the traverse, but not find corrsponding string.
1518 // This case is not allowed to happen.
1523 if (SubIndex
== Index
) {
1525 // According to the index of Lang string in SupportedLang string to get the language.
1526 // As this code will be invoked in RUNTIME, therefore there is not memory allocate/free operation.
1527 // In driver entry, it pre-allocates a runtime attribute memory to accommodate this string.
1529 mVariableModuleGlobal
->PlatformLang
[CompareLength
] = '\0';
1530 return CopyMem (mVariableModuleGlobal
->PlatformLang
, Supported
- CompareLength
, CompareLength
);
1535 // Skip ';' characters in Supported
1537 for (; *Supported
!= '\0' && *Supported
== ';'; Supported
++);
1543 Returns a pointer to an allocated buffer that contains the best matching language
1544 from a set of supported languages.
1546 This function supports both ISO 639-2 and RFC 4646 language codes, but language
1547 code types may not be mixed in a single call to this function. This function
1548 supports a variable argument list that allows the caller to pass in a prioritized
1549 list of language codes to test against all the language codes in SupportedLanguages.
1551 If SupportedLanguages is NULL, then ASSERT().
1553 @param[in] SupportedLanguages A pointer to a Null-terminated ASCII string that
1554 contains a set of language codes in the format
1555 specified by Iso639Language.
1556 @param[in] Iso639Language If not zero, then all language codes are assumed to be
1557 in ISO 639-2 format. If zero, then all language
1558 codes are assumed to be in RFC 4646 language format
1559 @param[in] ... A variable argument list that contains pointers to
1560 Null-terminated ASCII strings that contain one or more
1561 language codes in the format specified by Iso639Language.
1562 The first language code from each of these language
1563 code lists is used to determine if it is an exact or
1564 close match to any of the language codes in
1565 SupportedLanguages. Close matches only apply to RFC 4646
1566 language codes, and the matching algorithm from RFC 4647
1567 is used to determine if a close match is present. If
1568 an exact or close match is found, then the matching
1569 language code from SupportedLanguages is returned. If
1570 no matches are found, then the next variable argument
1571 parameter is evaluated. The variable argument list
1572 is terminated by a NULL.
1574 @retval NULL The best matching language could not be found in SupportedLanguages.
1575 @retval NULL There are not enough resources available to return the best matching
1577 @retval Other A pointer to a Null-terminated ASCII string that is the best matching
1578 language in SupportedLanguages.
1583 VariableGetBestLanguage (
1584 IN CONST CHAR8
*SupportedLanguages
,
1585 IN UINTN Iso639Language
,
1591 UINTN CompareLength
;
1592 UINTN LanguageLength
;
1593 CONST CHAR8
*Supported
;
1596 if (SupportedLanguages
== NULL
) {
1600 VA_START (Args
, Iso639Language
);
1601 while ((Language
= VA_ARG (Args
, CHAR8
*)) != NULL
) {
1603 // Default to ISO 639-2 mode
1606 LanguageLength
= MIN (3, AsciiStrLen (Language
));
1609 // If in RFC 4646 mode, then determine the length of the first RFC 4646 language code in Language
1611 if (Iso639Language
== 0) {
1612 for (LanguageLength
= 0; Language
[LanguageLength
] != 0 && Language
[LanguageLength
] != ';'; LanguageLength
++);
1616 // Trim back the length of Language used until it is empty
1618 while (LanguageLength
> 0) {
1620 // Loop through all language codes in SupportedLanguages
1622 for (Supported
= SupportedLanguages
; *Supported
!= '\0'; Supported
+= CompareLength
) {
1624 // In RFC 4646 mode, then Loop through all language codes in SupportedLanguages
1626 if (Iso639Language
== 0) {
1628 // Skip ';' characters in Supported
1630 for (; *Supported
!= '\0' && *Supported
== ';'; Supported
++);
1632 // Determine the length of the next language code in Supported
1634 for (CompareLength
= 0; Supported
[CompareLength
] != 0 && Supported
[CompareLength
] != ';'; CompareLength
++);
1636 // If Language is longer than the Supported, then skip to the next language
1638 if (LanguageLength
> CompareLength
) {
1643 // See if the first LanguageLength characters in Supported match Language
1645 if (AsciiStrnCmp (Supported
, Language
, LanguageLength
) == 0) {
1648 Buffer
= (Iso639Language
!= 0) ? mVariableModuleGlobal
->Lang
: mVariableModuleGlobal
->PlatformLang
;
1649 Buffer
[CompareLength
] = '\0';
1650 return CopyMem (Buffer
, Supported
, CompareLength
);
1654 if (Iso639Language
!= 0) {
1656 // If ISO 639 mode, then each language can only be tested once
1661 // If RFC 4646 mode, then trim Language from the right to the next '-' character
1663 for (LanguageLength
--; LanguageLength
> 0 && Language
[LanguageLength
] != '-'; LanguageLength
--);
1670 // No matches were found
1676 This function is to check if the remaining variable space is enough to set
1677 all Variables from argument list successfully. The purpose of the check
1678 is to keep the consistency of the Variables to be in variable storage.
1680 Note: Variables are assumed to be in same storage.
1681 The set sequence of Variables will be same with the sequence of VariableEntry from argument list,
1682 so follow the argument sequence to check the Variables.
1684 @param[in] Attributes Variable attributes for Variable entries.
1685 @param[in] Marker VA_LIST style variable argument list.
1686 The variable argument list with type VARIABLE_ENTRY_CONSISTENCY *.
1687 A NULL terminates the list. The VariableSize of
1688 VARIABLE_ENTRY_CONSISTENCY is the variable data size as input.
1689 It will be changed to variable total size as output.
1691 @retval TRUE Have enough variable space to set the Variables successfully.
1692 @retval FALSE No enough variable space to set the Variables successfully.
1697 CheckRemainingSpaceForConsistencyInternal (
1698 IN UINT32 Attributes
,
1704 VARIABLE_ENTRY_CONSISTENCY
*VariableEntry
;
1705 UINT64 MaximumVariableStorageSize
;
1706 UINT64 RemainingVariableStorageSize
;
1707 UINT64 MaximumVariableSize
;
1708 UINTN TotalNeededSize
;
1709 UINTN OriginalVarSize
;
1710 VARIABLE_STORE_HEADER
*VariableStoreHeader
;
1711 VARIABLE_POINTER_TRACK VariablePtrTrack
;
1712 VARIABLE_HEADER
*NextVariable
;
1717 // Non-Volatile related.
1719 VariableStoreHeader
= mNvVariableCache
;
1721 Status
= VariableServiceQueryVariableInfoInternal (
1723 &MaximumVariableStorageSize
,
1724 &RemainingVariableStorageSize
,
1725 &MaximumVariableSize
1727 ASSERT_EFI_ERROR (Status
);
1729 TotalNeededSize
= 0;
1730 VA_COPY (Args
, Marker
);
1731 VariableEntry
= VA_ARG (Args
, VARIABLE_ENTRY_CONSISTENCY
*);
1732 while (VariableEntry
!= NULL
) {
1734 // Calculate variable total size.
1736 VarNameSize
= StrSize (VariableEntry
->Name
);
1737 VarNameSize
+= GET_PAD_SIZE (VarNameSize
);
1738 VarDataSize
= VariableEntry
->VariableSize
;
1739 VarDataSize
+= GET_PAD_SIZE (VarDataSize
);
1740 VariableEntry
->VariableSize
= HEADER_ALIGN (GetVariableHeaderSize () + VarNameSize
+ VarDataSize
);
1742 TotalNeededSize
+= VariableEntry
->VariableSize
;
1743 VariableEntry
= VA_ARG (Args
, VARIABLE_ENTRY_CONSISTENCY
*);
1747 if (RemainingVariableStorageSize
>= TotalNeededSize
) {
1749 // Already have enough space.
1752 } else if (AtRuntime ()) {
1754 // At runtime, no reclaim.
1755 // The original variable space of Variables can't be reused.
1760 VA_COPY (Args
, Marker
);
1761 VariableEntry
= VA_ARG (Args
, VARIABLE_ENTRY_CONSISTENCY
*);
1762 while (VariableEntry
!= NULL
) {
1764 // Check if Variable[Index] has been present and get its size.
1766 OriginalVarSize
= 0;
1767 VariablePtrTrack
.StartPtr
= GetStartPointer (VariableStoreHeader
);
1768 VariablePtrTrack
.EndPtr
= GetEndPointer (VariableStoreHeader
);
1769 Status
= FindVariableEx (
1770 VariableEntry
->Name
,
1771 VariableEntry
->Guid
,
1775 if (!EFI_ERROR (Status
)) {
1777 // Get size of Variable[Index].
1779 NextVariable
= GetNextVariablePtr (VariablePtrTrack
.CurrPtr
);
1780 OriginalVarSize
= (UINTN
) NextVariable
- (UINTN
) VariablePtrTrack
.CurrPtr
;
1782 // Add the original size of Variable[Index] to remaining variable storage size.
1784 RemainingVariableStorageSize
+= OriginalVarSize
;
1786 if (VariableEntry
->VariableSize
> RemainingVariableStorageSize
) {
1788 // No enough space for Variable[Index].
1794 // Sub the (new) size of Variable[Index] from remaining variable storage size.
1796 RemainingVariableStorageSize
-= VariableEntry
->VariableSize
;
1797 VariableEntry
= VA_ARG (Args
, VARIABLE_ENTRY_CONSISTENCY
*);
1805 This function is to check if the remaining variable space is enough to set
1806 all Variables from argument list successfully. The purpose of the check
1807 is to keep the consistency of the Variables to be in variable storage.
1809 Note: Variables are assumed to be in same storage.
1810 The set sequence of Variables will be same with the sequence of VariableEntry from argument list,
1811 so follow the argument sequence to check the Variables.
1813 @param[in] Attributes Variable attributes for Variable entries.
1814 @param ... The variable argument list with type VARIABLE_ENTRY_CONSISTENCY *.
1815 A NULL terminates the list. The VariableSize of
1816 VARIABLE_ENTRY_CONSISTENCY is the variable data size as input.
1817 It will be changed to variable total size as output.
1819 @retval TRUE Have enough variable space to set the Variables successfully.
1820 @retval FALSE No enough variable space to set the Variables successfully.
1825 CheckRemainingSpaceForConsistency (
1826 IN UINT32 Attributes
,
1833 VA_START (Marker
, Attributes
);
1835 Return
= CheckRemainingSpaceForConsistencyInternal (Attributes
, Marker
);
1843 Hook the operations in PlatformLangCodes, LangCodes, PlatformLang and Lang.
1845 When setting Lang/LangCodes, simultaneously update PlatformLang/PlatformLangCodes.
1847 According to UEFI spec, PlatformLangCodes/LangCodes are only set once in firmware initialization,
1848 and are read-only. Therefore, in variable driver, only store the original value for other use.
1850 @param[in] VariableName Name of variable.
1852 @param[in] Data Variable data.
1854 @param[in] DataSize Size of data. 0 means delete.
1856 @retval EFI_SUCCESS The update operation is successful or ignored.
1857 @retval EFI_WRITE_PROTECTED Update PlatformLangCodes/LangCodes at runtime.
1858 @retval EFI_OUT_OF_RESOURCES No enough variable space to do the update operation.
1859 @retval Others Other errors happened during the update operation.
1863 AutoUpdateLangVariable (
1864 IN CHAR16
*VariableName
,
1870 CHAR8
*BestPlatformLang
;
1874 VARIABLE_POINTER_TRACK Variable
;
1875 BOOLEAN SetLanguageCodes
;
1876 VARIABLE_ENTRY_CONSISTENCY VariableEntry
[2];
1879 // Don't do updates for delete operation
1881 if (DataSize
== 0) {
1885 SetLanguageCodes
= FALSE
;
1887 if (StrCmp (VariableName
, EFI_PLATFORM_LANG_CODES_VARIABLE_NAME
) == 0) {
1889 // PlatformLangCodes is a volatile variable, so it can not be updated at runtime.
1892 return EFI_WRITE_PROTECTED
;
1895 SetLanguageCodes
= TRUE
;
1898 // According to UEFI spec, PlatformLangCodes is only set once in firmware initialization, and is read-only
1899 // Therefore, in variable driver, only store the original value for other use.
1901 if (mVariableModuleGlobal
->PlatformLangCodes
!= NULL
) {
1902 FreePool (mVariableModuleGlobal
->PlatformLangCodes
);
1904 mVariableModuleGlobal
->PlatformLangCodes
= AllocateRuntimeCopyPool (DataSize
, Data
);
1905 ASSERT (mVariableModuleGlobal
->PlatformLangCodes
!= NULL
);
1908 // PlatformLang holds a single language from PlatformLangCodes,
1909 // so the size of PlatformLangCodes is enough for the PlatformLang.
1911 if (mVariableModuleGlobal
->PlatformLang
!= NULL
) {
1912 FreePool (mVariableModuleGlobal
->PlatformLang
);
1914 mVariableModuleGlobal
->PlatformLang
= AllocateRuntimePool (DataSize
);
1915 ASSERT (mVariableModuleGlobal
->PlatformLang
!= NULL
);
1917 } else if (StrCmp (VariableName
, EFI_LANG_CODES_VARIABLE_NAME
) == 0) {
1919 // LangCodes is a volatile variable, so it can not be updated at runtime.
1922 return EFI_WRITE_PROTECTED
;
1925 SetLanguageCodes
= TRUE
;
1928 // According to UEFI spec, LangCodes is only set once in firmware initialization, and is read-only
1929 // Therefore, in variable driver, only store the original value for other use.
1931 if (mVariableModuleGlobal
->LangCodes
!= NULL
) {
1932 FreePool (mVariableModuleGlobal
->LangCodes
);
1934 mVariableModuleGlobal
->LangCodes
= AllocateRuntimeCopyPool (DataSize
, Data
);
1935 ASSERT (mVariableModuleGlobal
->LangCodes
!= NULL
);
1938 if (SetLanguageCodes
1939 && (mVariableModuleGlobal
->PlatformLangCodes
!= NULL
)
1940 && (mVariableModuleGlobal
->LangCodes
!= NULL
)) {
1942 // Update Lang if PlatformLang is already set
1943 // Update PlatformLang if Lang is already set
1945 Status
= FindVariable (EFI_PLATFORM_LANG_VARIABLE_NAME
, &gEfiGlobalVariableGuid
, &Variable
, &mVariableModuleGlobal
->VariableGlobal
, FALSE
);
1946 if (!EFI_ERROR (Status
)) {
1950 VariableName
= EFI_PLATFORM_LANG_VARIABLE_NAME
;
1951 Data
= GetVariableDataPtr (Variable
.CurrPtr
);
1952 DataSize
= DataSizeOfVariable (Variable
.CurrPtr
);
1954 Status
= FindVariable (EFI_LANG_VARIABLE_NAME
, &gEfiGlobalVariableGuid
, &Variable
, &mVariableModuleGlobal
->VariableGlobal
, FALSE
);
1955 if (!EFI_ERROR (Status
)) {
1957 // Update PlatformLang
1959 VariableName
= EFI_LANG_VARIABLE_NAME
;
1960 Data
= GetVariableDataPtr (Variable
.CurrPtr
);
1961 DataSize
= DataSizeOfVariable (Variable
.CurrPtr
);
1964 // Neither PlatformLang nor Lang is set, directly return
1971 Status
= EFI_SUCCESS
;
1974 // According to UEFI spec, "Lang" and "PlatformLang" is NV|BS|RT attributions.
1976 Attributes
= EFI_VARIABLE_NON_VOLATILE
| EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_RUNTIME_ACCESS
;
1978 if (StrCmp (VariableName
, EFI_PLATFORM_LANG_VARIABLE_NAME
) == 0) {
1980 // Update Lang when PlatformLangCodes/LangCodes were set.
1982 if ((mVariableModuleGlobal
->PlatformLangCodes
!= NULL
) && (mVariableModuleGlobal
->LangCodes
!= NULL
)) {
1984 // When setting PlatformLang, firstly get most matched language string from supported language codes.
1986 BestPlatformLang
= VariableGetBestLanguage (mVariableModuleGlobal
->PlatformLangCodes
, FALSE
, Data
, NULL
);
1987 if (BestPlatformLang
!= NULL
) {
1989 // Get the corresponding index in language codes.
1991 Index
= GetIndexFromSupportedLangCodes (mVariableModuleGlobal
->PlatformLangCodes
, BestPlatformLang
, FALSE
);
1994 // Get the corresponding ISO639 language tag according to RFC4646 language tag.
1996 BestLang
= GetLangFromSupportedLangCodes (mVariableModuleGlobal
->LangCodes
, Index
, TRUE
);
1999 // Check the variable space for both Lang and PlatformLang variable.
2001 VariableEntry
[0].VariableSize
= ISO_639_2_ENTRY_SIZE
+ 1;
2002 VariableEntry
[0].Guid
= &gEfiGlobalVariableGuid
;
2003 VariableEntry
[0].Name
= EFI_LANG_VARIABLE_NAME
;
2005 VariableEntry
[1].VariableSize
= AsciiStrSize (BestPlatformLang
);
2006 VariableEntry
[1].Guid
= &gEfiGlobalVariableGuid
;
2007 VariableEntry
[1].Name
= EFI_PLATFORM_LANG_VARIABLE_NAME
;
2008 if (!CheckRemainingSpaceForConsistency (VARIABLE_ATTRIBUTE_NV_BS_RT
, &VariableEntry
[0], &VariableEntry
[1], NULL
)) {
2010 // No enough variable space to set both Lang and PlatformLang successfully.
2012 Status
= EFI_OUT_OF_RESOURCES
;
2015 // Successfully convert PlatformLang to Lang, and set the BestLang value into Lang variable simultaneously.
2017 FindVariable (EFI_LANG_VARIABLE_NAME
, &gEfiGlobalVariableGuid
, &Variable
, &mVariableModuleGlobal
->VariableGlobal
, FALSE
);
2019 Status
= UpdateVariable (EFI_LANG_VARIABLE_NAME
, &gEfiGlobalVariableGuid
, BestLang
,
2020 ISO_639_2_ENTRY_SIZE
+ 1, Attributes
, 0, 0, &Variable
, NULL
);
2023 DEBUG ((EFI_D_INFO
, "Variable Driver Auto Update PlatformLang, PlatformLang:%a, Lang:%a Status: %r\n", BestPlatformLang
, BestLang
, Status
));
2027 } else if (StrCmp (VariableName
, EFI_LANG_VARIABLE_NAME
) == 0) {
2029 // Update PlatformLang when PlatformLangCodes/LangCodes were set.
2031 if ((mVariableModuleGlobal
->PlatformLangCodes
!= NULL
) && (mVariableModuleGlobal
->LangCodes
!= NULL
)) {
2033 // When setting Lang, firstly get most matched language string from supported language codes.
2035 BestLang
= VariableGetBestLanguage (mVariableModuleGlobal
->LangCodes
, TRUE
, Data
, NULL
);
2036 if (BestLang
!= NULL
) {
2038 // Get the corresponding index in language codes.
2040 Index
= GetIndexFromSupportedLangCodes (mVariableModuleGlobal
->LangCodes
, BestLang
, TRUE
);
2043 // Get the corresponding RFC4646 language tag according to ISO639 language tag.
2045 BestPlatformLang
= GetLangFromSupportedLangCodes (mVariableModuleGlobal
->PlatformLangCodes
, Index
, FALSE
);
2048 // Check the variable space for both PlatformLang and Lang variable.
2050 VariableEntry
[0].VariableSize
= AsciiStrSize (BestPlatformLang
);
2051 VariableEntry
[0].Guid
= &gEfiGlobalVariableGuid
;
2052 VariableEntry
[0].Name
= EFI_PLATFORM_LANG_VARIABLE_NAME
;
2054 VariableEntry
[1].VariableSize
= ISO_639_2_ENTRY_SIZE
+ 1;
2055 VariableEntry
[1].Guid
= &gEfiGlobalVariableGuid
;
2056 VariableEntry
[1].Name
= EFI_LANG_VARIABLE_NAME
;
2057 if (!CheckRemainingSpaceForConsistency (VARIABLE_ATTRIBUTE_NV_BS_RT
, &VariableEntry
[0], &VariableEntry
[1], NULL
)) {
2059 // No enough variable space to set both PlatformLang and Lang successfully.
2061 Status
= EFI_OUT_OF_RESOURCES
;
2064 // Successfully convert Lang to PlatformLang, and set the BestPlatformLang value into PlatformLang variable simultaneously.
2066 FindVariable (EFI_PLATFORM_LANG_VARIABLE_NAME
, &gEfiGlobalVariableGuid
, &Variable
, &mVariableModuleGlobal
->VariableGlobal
, FALSE
);
2068 Status
= UpdateVariable (EFI_PLATFORM_LANG_VARIABLE_NAME
, &gEfiGlobalVariableGuid
, BestPlatformLang
,
2069 AsciiStrSize (BestPlatformLang
), Attributes
, 0, 0, &Variable
, NULL
);
2072 DEBUG ((EFI_D_INFO
, "Variable Driver Auto Update Lang, Lang:%a, PlatformLang:%a Status: %r\n", BestLang
, BestPlatformLang
, Status
));
2077 if (SetLanguageCodes
) {
2079 // Continue to set PlatformLangCodes or LangCodes.
2088 Compare two EFI_TIME data.
2091 @param FirstTime A pointer to the first EFI_TIME data.
2092 @param SecondTime A pointer to the second EFI_TIME data.
2094 @retval TRUE The FirstTime is not later than the SecondTime.
2095 @retval FALSE The FirstTime is later than the SecondTime.
2099 VariableCompareTimeStampInternal (
2100 IN EFI_TIME
*FirstTime
,
2101 IN EFI_TIME
*SecondTime
2104 if (FirstTime
->Year
!= SecondTime
->Year
) {
2105 return (BOOLEAN
) (FirstTime
->Year
< SecondTime
->Year
);
2106 } else if (FirstTime
->Month
!= SecondTime
->Month
) {
2107 return (BOOLEAN
) (FirstTime
->Month
< SecondTime
->Month
);
2108 } else if (FirstTime
->Day
!= SecondTime
->Day
) {
2109 return (BOOLEAN
) (FirstTime
->Day
< SecondTime
->Day
);
2110 } else if (FirstTime
->Hour
!= SecondTime
->Hour
) {
2111 return (BOOLEAN
) (FirstTime
->Hour
< SecondTime
->Hour
);
2112 } else if (FirstTime
->Minute
!= SecondTime
->Minute
) {
2113 return (BOOLEAN
) (FirstTime
->Minute
< SecondTime
->Minute
);
2116 return (BOOLEAN
) (FirstTime
->Second
<= SecondTime
->Second
);
2120 Update the variable region with Variable information. If EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS is set,
2121 index of associated public key is needed.
2123 @param[in] VariableName Name of variable.
2124 @param[in] VendorGuid Guid of variable.
2125 @param[in] Data Variable data.
2126 @param[in] DataSize Size of data. 0 means delete.
2127 @param[in] Attributes Attributes of the variable.
2128 @param[in] KeyIndex Index of associated public key.
2129 @param[in] MonotonicCount Value of associated monotonic count.
2130 @param[in, out] CacheVariable The variable information which is used to keep track of variable usage.
2131 @param[in] TimeStamp Value of associated TimeStamp.
2133 @retval EFI_SUCCESS The update operation is success.
2134 @retval EFI_OUT_OF_RESOURCES Variable region is full, can not write other data into this region.
2139 IN CHAR16
*VariableName
,
2140 IN EFI_GUID
*VendorGuid
,
2143 IN UINT32 Attributes OPTIONAL
,
2144 IN UINT32 KeyIndex OPTIONAL
,
2145 IN UINT64 MonotonicCount OPTIONAL
,
2146 IN OUT VARIABLE_POINTER_TRACK
*CacheVariable
,
2147 IN EFI_TIME
*TimeStamp OPTIONAL
2151 VARIABLE_HEADER
*NextVariable
;
2154 UINTN VarNameOffset
;
2155 UINTN VarDataOffset
;
2159 EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*Fvb
;
2161 VARIABLE_POINTER_TRACK
*Variable
;
2162 VARIABLE_POINTER_TRACK NvVariable
;
2163 VARIABLE_STORE_HEADER
*VariableStoreHeader
;
2164 UINT8
*BufferForMerge
;
2165 UINTN MergedBufSize
;
2168 BOOLEAN IsCommonVariable
;
2169 BOOLEAN IsCommonUserVariable
;
2170 AUTHENTICATED_VARIABLE_HEADER
*AuthVariable
;
2172 if (mVariableModuleGlobal
->FvbInstance
== NULL
&& !mVariableModuleGlobal
->VariableGlobal
.EmuNvMode
) {
2174 // The FVB protocol is not ready, so the EFI_VARIABLE_WRITE_ARCH_PROTOCOL is not installed.
2176 if ((Attributes
& EFI_VARIABLE_NON_VOLATILE
) != 0) {
2178 // Trying to update NV variable prior to the installation of EFI_VARIABLE_WRITE_ARCH_PROTOCOL
2180 DEBUG ((EFI_D_ERROR
, "Update NV variable before EFI_VARIABLE_WRITE_ARCH_PROTOCOL ready - %r\n", EFI_NOT_AVAILABLE_YET
));
2181 return EFI_NOT_AVAILABLE_YET
;
2182 } else if ((Attributes
& VARIABLE_ATTRIBUTE_AT_AW
) != 0) {
2184 // Trying to update volatile authenticated variable prior to the installation of EFI_VARIABLE_WRITE_ARCH_PROTOCOL
2185 // The authenticated variable perhaps is not initialized, just return here.
2187 DEBUG ((EFI_D_ERROR
, "Update AUTH variable before EFI_VARIABLE_WRITE_ARCH_PROTOCOL ready - %r\n", EFI_NOT_AVAILABLE_YET
));
2188 return EFI_NOT_AVAILABLE_YET
;
2193 // Check if CacheVariable points to the variable in variable HOB.
2194 // If yes, let CacheVariable points to the variable in NV variable cache.
2196 if ((CacheVariable
->CurrPtr
!= NULL
) &&
2197 (mVariableModuleGlobal
->VariableGlobal
.HobVariableBase
!= 0) &&
2198 (CacheVariable
->StartPtr
== GetStartPointer ((VARIABLE_STORE_HEADER
*) (UINTN
) mVariableModuleGlobal
->VariableGlobal
.HobVariableBase
))
2200 CacheVariable
->StartPtr
= GetStartPointer (mNvVariableCache
);
2201 CacheVariable
->EndPtr
= GetEndPointer (mNvVariableCache
);
2202 CacheVariable
->Volatile
= FALSE
;
2203 Status
= FindVariableEx (VariableName
, VendorGuid
, FALSE
, CacheVariable
);
2204 if (CacheVariable
->CurrPtr
== NULL
|| EFI_ERROR (Status
)) {
2206 // There is no matched variable in NV variable cache.
2208 if ((((Attributes
& EFI_VARIABLE_APPEND_WRITE
) == 0) && (DataSize
== 0)) || (Attributes
== 0)) {
2210 // It is to delete variable,
2211 // go to delete this variable in variable HOB and
2212 // try to flush other variables from HOB to flash.
2214 UpdateVariableInfo (VariableName
, VendorGuid
, FALSE
, FALSE
, FALSE
, TRUE
, FALSE
);
2215 FlushHobVariableToFlash (VariableName
, VendorGuid
);
2221 if ((CacheVariable
->CurrPtr
== NULL
) || CacheVariable
->Volatile
) {
2222 Variable
= CacheVariable
;
2225 // Update/Delete existing NV variable.
2226 // CacheVariable points to the variable in the memory copy of Flash area
2227 // Now let Variable points to the same variable in Flash area.
2229 VariableStoreHeader
= (VARIABLE_STORE_HEADER
*) ((UINTN
) mVariableModuleGlobal
->VariableGlobal
.NonVolatileVariableBase
);
2230 Variable
= &NvVariable
;
2231 Variable
->StartPtr
= GetStartPointer (VariableStoreHeader
);
2232 Variable
->EndPtr
= (VARIABLE_HEADER
*)((UINTN
)Variable
->StartPtr
+ ((UINTN
)CacheVariable
->EndPtr
- (UINTN
)CacheVariable
->StartPtr
));
2234 Variable
->CurrPtr
= (VARIABLE_HEADER
*)((UINTN
)Variable
->StartPtr
+ ((UINTN
)CacheVariable
->CurrPtr
- (UINTN
)CacheVariable
->StartPtr
));
2235 if (CacheVariable
->InDeletedTransitionPtr
!= NULL
) {
2236 Variable
->InDeletedTransitionPtr
= (VARIABLE_HEADER
*)((UINTN
)Variable
->StartPtr
+ ((UINTN
)CacheVariable
->InDeletedTransitionPtr
- (UINTN
)CacheVariable
->StartPtr
));
2238 Variable
->InDeletedTransitionPtr
= NULL
;
2240 Variable
->Volatile
= FALSE
;
2243 Fvb
= mVariableModuleGlobal
->FvbInstance
;
2246 // Tricky part: Use scratch data area at the end of volatile variable store
2247 // as a temporary storage.
2249 NextVariable
= GetEndPointer ((VARIABLE_STORE_HEADER
*) ((UINTN
) mVariableModuleGlobal
->VariableGlobal
.VolatileVariableBase
));
2250 ScratchSize
= mVariableModuleGlobal
->ScratchBufferSize
;
2251 SetMem (NextVariable
, ScratchSize
, 0xff);
2254 if (Variable
->CurrPtr
!= NULL
) {
2256 // Update/Delete existing variable.
2260 // If AtRuntime and the variable is Volatile and Runtime Access,
2261 // the volatile is ReadOnly, and SetVariable should be aborted and
2262 // return EFI_WRITE_PROTECTED.
2264 if (Variable
->Volatile
) {
2265 Status
= EFI_WRITE_PROTECTED
;
2269 // Only variable that have NV attributes can be updated/deleted in Runtime.
2271 if ((CacheVariable
->CurrPtr
->Attributes
& EFI_VARIABLE_NON_VOLATILE
) == 0) {
2272 Status
= EFI_INVALID_PARAMETER
;
2277 // Only variable that have RT attributes can be updated/deleted in Runtime.
2279 if ((CacheVariable
->CurrPtr
->Attributes
& EFI_VARIABLE_RUNTIME_ACCESS
) == 0) {
2280 Status
= EFI_INVALID_PARAMETER
;
2286 // Setting a data variable with no access, or zero DataSize attributes
2287 // causes it to be deleted.
2288 // When the EFI_VARIABLE_APPEND_WRITE attribute is set, DataSize of zero will
2289 // not delete the variable.
2291 if ((((Attributes
& EFI_VARIABLE_APPEND_WRITE
) == 0) && (DataSize
== 0))|| ((Attributes
& (EFI_VARIABLE_RUNTIME_ACCESS
| EFI_VARIABLE_BOOTSERVICE_ACCESS
)) == 0)) {
2292 if (Variable
->InDeletedTransitionPtr
!= NULL
) {
2294 // Both ADDED and IN_DELETED_TRANSITION variable are present,
2295 // set IN_DELETED_TRANSITION one to DELETED state first.
2297 ASSERT (CacheVariable
->InDeletedTransitionPtr
!= NULL
);
2298 State
= CacheVariable
->InDeletedTransitionPtr
->State
;
2299 State
&= VAR_DELETED
;
2300 Status
= UpdateVariableStore (
2301 &mVariableModuleGlobal
->VariableGlobal
,
2305 (UINTN
) &Variable
->InDeletedTransitionPtr
->State
,
2309 if (!EFI_ERROR (Status
)) {
2310 if (!Variable
->Volatile
) {
2311 CacheVariable
->InDeletedTransitionPtr
->State
= State
;
2318 State
= CacheVariable
->CurrPtr
->State
;
2319 State
&= VAR_DELETED
;
2321 Status
= UpdateVariableStore (
2322 &mVariableModuleGlobal
->VariableGlobal
,
2326 (UINTN
) &Variable
->CurrPtr
->State
,
2330 if (!EFI_ERROR (Status
)) {
2331 UpdateVariableInfo (VariableName
, VendorGuid
, Variable
->Volatile
, FALSE
, FALSE
, TRUE
, FALSE
);
2332 if (!Variable
->Volatile
) {
2333 CacheVariable
->CurrPtr
->State
= State
;
2334 FlushHobVariableToFlash (VariableName
, VendorGuid
);
2340 // If the variable is marked valid, and the same data has been passed in,
2341 // then return to the caller immediately.
2343 if (DataSizeOfVariable (CacheVariable
->CurrPtr
) == DataSize
&&
2344 (CompareMem (Data
, GetVariableDataPtr (CacheVariable
->CurrPtr
), DataSize
) == 0) &&
2345 ((Attributes
& EFI_VARIABLE_APPEND_WRITE
) == 0) &&
2346 (TimeStamp
== NULL
)) {
2348 // Variable content unchanged and no need to update timestamp, just return.
2350 UpdateVariableInfo (VariableName
, VendorGuid
, Variable
->Volatile
, FALSE
, TRUE
, FALSE
, FALSE
);
2351 Status
= EFI_SUCCESS
;
2353 } else if ((CacheVariable
->CurrPtr
->State
== VAR_ADDED
) ||
2354 (CacheVariable
->CurrPtr
->State
== (VAR_ADDED
& VAR_IN_DELETED_TRANSITION
))) {
2357 // EFI_VARIABLE_APPEND_WRITE attribute only effects for existing variable.
2359 if ((Attributes
& EFI_VARIABLE_APPEND_WRITE
) != 0) {
2361 // NOTE: From 0 to DataOffset of NextVariable is reserved for Variable Header and Name.
2362 // From DataOffset of NextVariable is to save the existing variable data.
2364 DataOffset
= GetVariableDataOffset (CacheVariable
->CurrPtr
);
2365 BufferForMerge
= (UINT8
*) ((UINTN
) NextVariable
+ DataOffset
);
2366 CopyMem (BufferForMerge
, (UINT8
*) ((UINTN
) CacheVariable
->CurrPtr
+ DataOffset
), DataSizeOfVariable (CacheVariable
->CurrPtr
));
2369 // Set Max Auth/Non-Volatile/Volatile Variable Data Size as default MaxDataSize.
2371 if ((Attributes
& VARIABLE_ATTRIBUTE_AT_AW
) != 0) {
2372 MaxDataSize
= mVariableModuleGlobal
->MaxAuthVariableSize
- DataOffset
;
2373 } else if ((Attributes
& EFI_VARIABLE_NON_VOLATILE
) != 0) {
2374 MaxDataSize
= mVariableModuleGlobal
->MaxVariableSize
- DataOffset
;
2376 MaxDataSize
= mVariableModuleGlobal
->MaxVolatileVariableSize
- DataOffset
;
2380 // Append the new data to the end of existing data.
2381 // Max Harware error record variable data size is different from common/auth variable.
2383 if ((Attributes
& EFI_VARIABLE_HARDWARE_ERROR_RECORD
) == EFI_VARIABLE_HARDWARE_ERROR_RECORD
) {
2384 MaxDataSize
= PcdGet32 (PcdMaxHardwareErrorVariableSize
) - DataOffset
;
2387 if (DataSizeOfVariable (CacheVariable
->CurrPtr
) + DataSize
> MaxDataSize
) {
2389 // Existing data size + new data size exceed maximum variable size limitation.
2391 Status
= EFI_INVALID_PARAMETER
;
2394 CopyMem ((UINT8
*) ((UINTN
) BufferForMerge
+ DataSizeOfVariable (CacheVariable
->CurrPtr
)), Data
, DataSize
);
2395 MergedBufSize
= DataSizeOfVariable (CacheVariable
->CurrPtr
) + DataSize
;
2398 // BufferForMerge(from DataOffset of NextVariable) has included the merged existing and new data.
2400 Data
= BufferForMerge
;
2401 DataSize
= MergedBufSize
;
2406 // Mark the old variable as in delete transition.
2408 State
= CacheVariable
->CurrPtr
->State
;
2409 State
&= VAR_IN_DELETED_TRANSITION
;
2411 Status
= UpdateVariableStore (
2412 &mVariableModuleGlobal
->VariableGlobal
,
2416 (UINTN
) &Variable
->CurrPtr
->State
,
2420 if (EFI_ERROR (Status
)) {
2423 if (!Variable
->Volatile
) {
2424 CacheVariable
->CurrPtr
->State
= State
;
2429 // Not found existing variable. Create a new variable.
2432 if ((DataSize
== 0) && ((Attributes
& EFI_VARIABLE_APPEND_WRITE
) != 0)) {
2433 Status
= EFI_SUCCESS
;
2438 // Make sure we are trying to create a new variable.
2439 // Setting a data variable with zero DataSize or no access attributes means to delete it.
2441 if (DataSize
== 0 || (Attributes
& (EFI_VARIABLE_RUNTIME_ACCESS
| EFI_VARIABLE_BOOTSERVICE_ACCESS
)) == 0) {
2442 Status
= EFI_NOT_FOUND
;
2447 // Only variable have NV|RT attribute can be created in Runtime.
2450 (((Attributes
& EFI_VARIABLE_RUNTIME_ACCESS
) == 0) || ((Attributes
& EFI_VARIABLE_NON_VOLATILE
) == 0))) {
2451 Status
= EFI_INVALID_PARAMETER
;
2457 // Function part - create a new variable and copy the data.
2458 // Both update a variable and create a variable will come here.
2460 NextVariable
->StartId
= VARIABLE_DATA
;
2462 // NextVariable->State = VAR_ADDED;
2464 NextVariable
->Reserved
= 0;
2465 if (mVariableModuleGlobal
->VariableGlobal
.AuthFormat
) {
2466 AuthVariable
= (AUTHENTICATED_VARIABLE_HEADER
*) NextVariable
;
2467 AuthVariable
->PubKeyIndex
= KeyIndex
;
2468 AuthVariable
->MonotonicCount
= MonotonicCount
;
2469 ZeroMem (&AuthVariable
->TimeStamp
, sizeof (EFI_TIME
));
2471 if (((Attributes
& EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS
) != 0) &&
2472 (TimeStamp
!= NULL
)) {
2473 if ((Attributes
& EFI_VARIABLE_APPEND_WRITE
) == 0) {
2474 CopyMem (&AuthVariable
->TimeStamp
, TimeStamp
, sizeof (EFI_TIME
));
2477 // In the case when the EFI_VARIABLE_APPEND_WRITE attribute is set, only
2478 // when the new TimeStamp value is later than the current timestamp associated
2479 // with the variable, we need associate the new timestamp with the updated value.
2481 if (Variable
->CurrPtr
!= NULL
) {
2482 if (VariableCompareTimeStampInternal (&(((AUTHENTICATED_VARIABLE_HEADER
*) CacheVariable
->CurrPtr
)->TimeStamp
), TimeStamp
)) {
2483 CopyMem (&AuthVariable
->TimeStamp
, TimeStamp
, sizeof (EFI_TIME
));
2485 CopyMem (&AuthVariable
->TimeStamp
, &(((AUTHENTICATED_VARIABLE_HEADER
*) CacheVariable
->CurrPtr
)->TimeStamp
), sizeof (EFI_TIME
));
2493 // The EFI_VARIABLE_APPEND_WRITE attribute will never be set in the returned
2494 // Attributes bitmask parameter of a GetVariable() call.
2496 NextVariable
->Attributes
= Attributes
& (~EFI_VARIABLE_APPEND_WRITE
);
2498 VarNameOffset
= GetVariableHeaderSize ();
2499 VarNameSize
= StrSize (VariableName
);
2501 (UINT8
*) ((UINTN
) NextVariable
+ VarNameOffset
),
2505 VarDataOffset
= VarNameOffset
+ VarNameSize
+ GET_PAD_SIZE (VarNameSize
);
2508 // If DataReady is TRUE, it means the variable data has been saved into
2509 // NextVariable during EFI_VARIABLE_APPEND_WRITE operation preparation.
2513 (UINT8
*) ((UINTN
) NextVariable
+ VarDataOffset
),
2519 CopyMem (GetVendorGuidPtr (NextVariable
), VendorGuid
, sizeof (EFI_GUID
));
2521 // There will be pad bytes after Data, the NextVariable->NameSize and
2522 // NextVariable->DataSize should not include pad size so that variable
2523 // service can get actual size in GetVariable.
2525 SetNameSizeOfVariable (NextVariable
, VarNameSize
);
2526 SetDataSizeOfVariable (NextVariable
, DataSize
);
2529 // The actual size of the variable that stores in storage should
2530 // include pad size.
2532 VarSize
= VarDataOffset
+ DataSize
+ GET_PAD_SIZE (DataSize
);
2533 if ((Attributes
& EFI_VARIABLE_NON_VOLATILE
) != 0) {
2535 // Create a nonvolatile variable.
2539 IsCommonVariable
= FALSE
;
2540 IsCommonUserVariable
= FALSE
;
2541 if ((Attributes
& EFI_VARIABLE_HARDWARE_ERROR_RECORD
) == 0) {
2542 IsCommonVariable
= TRUE
;
2543 IsCommonUserVariable
= IsUserVariable (NextVariable
);
2545 if ((((Attributes
& EFI_VARIABLE_HARDWARE_ERROR_RECORD
) != 0)
2546 && ((VarSize
+ mVariableModuleGlobal
->HwErrVariableTotalSize
) > PcdGet32 (PcdHwErrStorageSize
)))
2547 || (IsCommonVariable
&& ((VarSize
+ mVariableModuleGlobal
->CommonVariableTotalSize
) > mVariableModuleGlobal
->CommonVariableSpace
))
2548 || (IsCommonVariable
&& AtRuntime () && ((VarSize
+ mVariableModuleGlobal
->CommonVariableTotalSize
) > mVariableModuleGlobal
->CommonRuntimeVariableSpace
))
2549 || (IsCommonUserVariable
&& ((VarSize
+ mVariableModuleGlobal
->CommonUserVariableTotalSize
) > mVariableModuleGlobal
->CommonMaxUserVariableSpace
))) {
2551 if (IsCommonUserVariable
&& ((VarSize
+ mVariableModuleGlobal
->CommonUserVariableTotalSize
) > mVariableModuleGlobal
->CommonMaxUserVariableSpace
)) {
2552 RecordVarErrorFlag (VAR_ERROR_FLAG_USER_ERROR
, VariableName
, VendorGuid
, Attributes
, VarSize
);
2554 if (IsCommonVariable
&& ((VarSize
+ mVariableModuleGlobal
->CommonVariableTotalSize
) > mVariableModuleGlobal
->CommonRuntimeVariableSpace
)) {
2555 RecordVarErrorFlag (VAR_ERROR_FLAG_SYSTEM_ERROR
, VariableName
, VendorGuid
, Attributes
, VarSize
);
2557 Status
= EFI_OUT_OF_RESOURCES
;
2561 // Perform garbage collection & reclaim operation, and integrate the new variable at the same time.
2564 mVariableModuleGlobal
->VariableGlobal
.NonVolatileVariableBase
,
2565 &mVariableModuleGlobal
->NonVolatileLastVariableOffset
,
2569 HEADER_ALIGN (VarSize
)
2571 if (!EFI_ERROR (Status
)) {
2573 // The new variable has been integrated successfully during reclaiming.
2575 if (Variable
->CurrPtr
!= NULL
) {
2576 CacheVariable
->CurrPtr
= (VARIABLE_HEADER
*)((UINTN
) CacheVariable
->StartPtr
+ ((UINTN
) Variable
->CurrPtr
- (UINTN
) Variable
->StartPtr
));
2577 CacheVariable
->InDeletedTransitionPtr
= NULL
;
2579 UpdateVariableInfo (VariableName
, VendorGuid
, FALSE
, FALSE
, TRUE
, FALSE
, FALSE
);
2580 FlushHobVariableToFlash (VariableName
, VendorGuid
);
2582 if (IsCommonUserVariable
&& ((VarSize
+ mVariableModuleGlobal
->CommonUserVariableTotalSize
) > mVariableModuleGlobal
->CommonMaxUserVariableSpace
)) {
2583 RecordVarErrorFlag (VAR_ERROR_FLAG_USER_ERROR
, VariableName
, VendorGuid
, Attributes
, VarSize
);
2585 if (IsCommonVariable
&& ((VarSize
+ mVariableModuleGlobal
->CommonVariableTotalSize
) > mVariableModuleGlobal
->CommonVariableSpace
)) {
2586 RecordVarErrorFlag (VAR_ERROR_FLAG_SYSTEM_ERROR
, VariableName
, VendorGuid
, Attributes
, VarSize
);
2592 if (!mVariableModuleGlobal
->VariableGlobal
.EmuNvMode
) {
2595 // 1. Write variable header
2596 // 2. Set variable state to header valid
2597 // 3. Write variable data
2598 // 4. Set variable state to valid
2603 Status
= UpdateVariableStore (
2604 &mVariableModuleGlobal
->VariableGlobal
,
2608 mVariableModuleGlobal
->NonVolatileLastVariableOffset
,
2609 (UINT32
) GetVariableHeaderSize (),
2610 (UINT8
*) NextVariable
2613 if (EFI_ERROR (Status
)) {
2620 NextVariable
->State
= VAR_HEADER_VALID_ONLY
;
2621 Status
= UpdateVariableStore (
2622 &mVariableModuleGlobal
->VariableGlobal
,
2626 mVariableModuleGlobal
->NonVolatileLastVariableOffset
+ OFFSET_OF (VARIABLE_HEADER
, State
),
2628 &NextVariable
->State
2631 if (EFI_ERROR (Status
)) {
2637 Status
= UpdateVariableStore (
2638 &mVariableModuleGlobal
->VariableGlobal
,
2642 mVariableModuleGlobal
->NonVolatileLastVariableOffset
+ GetVariableHeaderSize (),
2643 (UINT32
) (VarSize
- GetVariableHeaderSize ()),
2644 (UINT8
*) NextVariable
+ GetVariableHeaderSize ()
2647 if (EFI_ERROR (Status
)) {
2653 NextVariable
->State
= VAR_ADDED
;
2654 Status
= UpdateVariableStore (
2655 &mVariableModuleGlobal
->VariableGlobal
,
2659 mVariableModuleGlobal
->NonVolatileLastVariableOffset
+ OFFSET_OF (VARIABLE_HEADER
, State
),
2661 &NextVariable
->State
2664 if (EFI_ERROR (Status
)) {
2669 // Update the memory copy of Flash region.
2671 CopyMem ((UINT8
*)mNvVariableCache
+ mVariableModuleGlobal
->NonVolatileLastVariableOffset
, (UINT8
*)NextVariable
, VarSize
);
2674 // Emulated non-volatile variable mode.
2676 NextVariable
->State
= VAR_ADDED
;
2677 Status
= UpdateVariableStore (
2678 &mVariableModuleGlobal
->VariableGlobal
,
2682 mVariableModuleGlobal
->NonVolatileLastVariableOffset
,
2684 (UINT8
*) NextVariable
2687 if (EFI_ERROR (Status
)) {
2692 mVariableModuleGlobal
->NonVolatileLastVariableOffset
+= HEADER_ALIGN (VarSize
);
2694 if ((Attributes
& EFI_VARIABLE_HARDWARE_ERROR_RECORD
) != 0) {
2695 mVariableModuleGlobal
->HwErrVariableTotalSize
+= HEADER_ALIGN (VarSize
);
2697 mVariableModuleGlobal
->CommonVariableTotalSize
+= HEADER_ALIGN (VarSize
);
2698 if (IsCommonUserVariable
) {
2699 mVariableModuleGlobal
->CommonUserVariableTotalSize
+= HEADER_ALIGN (VarSize
);
2704 // Create a volatile variable.
2708 if ((UINT32
) (VarSize
+ mVariableModuleGlobal
->VolatileLastVariableOffset
) >
2709 ((VARIABLE_STORE_HEADER
*) ((UINTN
) (mVariableModuleGlobal
->VariableGlobal
.VolatileVariableBase
)))->Size
) {
2711 // Perform garbage collection & reclaim operation, and integrate the new variable at the same time.
2714 mVariableModuleGlobal
->VariableGlobal
.VolatileVariableBase
,
2715 &mVariableModuleGlobal
->VolatileLastVariableOffset
,
2719 HEADER_ALIGN (VarSize
)
2721 if (!EFI_ERROR (Status
)) {
2723 // The new variable has been integrated successfully during reclaiming.
2725 if (Variable
->CurrPtr
!= NULL
) {
2726 CacheVariable
->CurrPtr
= (VARIABLE_HEADER
*)((UINTN
) CacheVariable
->StartPtr
+ ((UINTN
) Variable
->CurrPtr
- (UINTN
) Variable
->StartPtr
));
2727 CacheVariable
->InDeletedTransitionPtr
= NULL
;
2729 UpdateVariableInfo (VariableName
, VendorGuid
, TRUE
, FALSE
, TRUE
, FALSE
, FALSE
);
2734 NextVariable
->State
= VAR_ADDED
;
2735 Status
= UpdateVariableStore (
2736 &mVariableModuleGlobal
->VariableGlobal
,
2740 mVariableModuleGlobal
->VolatileLastVariableOffset
,
2742 (UINT8
*) NextVariable
2745 if (EFI_ERROR (Status
)) {
2749 mVariableModuleGlobal
->VolatileLastVariableOffset
+= HEADER_ALIGN (VarSize
);
2753 // Mark the old variable as deleted.
2755 if (!EFI_ERROR (Status
) && Variable
->CurrPtr
!= NULL
) {
2756 if (Variable
->InDeletedTransitionPtr
!= NULL
) {
2758 // Both ADDED and IN_DELETED_TRANSITION old variable are present,
2759 // set IN_DELETED_TRANSITION one to DELETED state first.
2761 ASSERT (CacheVariable
->InDeletedTransitionPtr
!= NULL
);
2762 State
= CacheVariable
->InDeletedTransitionPtr
->State
;
2763 State
&= VAR_DELETED
;
2764 Status
= UpdateVariableStore (
2765 &mVariableModuleGlobal
->VariableGlobal
,
2769 (UINTN
) &Variable
->InDeletedTransitionPtr
->State
,
2773 if (!EFI_ERROR (Status
)) {
2774 if (!Variable
->Volatile
) {
2775 CacheVariable
->InDeletedTransitionPtr
->State
= State
;
2782 State
= CacheVariable
->CurrPtr
->State
;
2783 State
&= VAR_DELETED
;
2785 Status
= UpdateVariableStore (
2786 &mVariableModuleGlobal
->VariableGlobal
,
2790 (UINTN
) &Variable
->CurrPtr
->State
,
2794 if (!EFI_ERROR (Status
) && !Variable
->Volatile
) {
2795 CacheVariable
->CurrPtr
->State
= State
;
2799 if (!EFI_ERROR (Status
)) {
2800 UpdateVariableInfo (VariableName
, VendorGuid
, Volatile
, FALSE
, TRUE
, FALSE
, FALSE
);
2802 FlushHobVariableToFlash (VariableName
, VendorGuid
);
2812 This code finds variable in storage blocks (Volatile or Non-Volatile).
2814 Caution: This function may receive untrusted input.
2815 This function may be invoked in SMM mode, and datasize is external input.
2816 This function will do basic validation, before parse the data.
2818 @param VariableName Name of Variable to be found.
2819 @param VendorGuid Variable vendor GUID.
2820 @param Attributes Attribute value of the variable found.
2821 @param DataSize Size of Data found. If size is less than the
2822 data, this value contains the required size.
2823 @param Data The buffer to return the contents of the variable. May be NULL
2824 with a zero DataSize in order to determine the size buffer needed.
2826 @return EFI_INVALID_PARAMETER Invalid parameter.
2827 @return EFI_SUCCESS Find the specified variable.
2828 @return EFI_NOT_FOUND Not found.
2829 @return EFI_BUFFER_TO_SMALL DataSize is too small for the result.
2834 VariableServiceGetVariable (
2835 IN CHAR16
*VariableName
,
2836 IN EFI_GUID
*VendorGuid
,
2837 OUT UINT32
*Attributes OPTIONAL
,
2838 IN OUT UINTN
*DataSize
,
2839 OUT VOID
*Data OPTIONAL
2843 VARIABLE_POINTER_TRACK Variable
;
2846 if (VariableName
== NULL
|| VendorGuid
== NULL
|| DataSize
== NULL
) {
2847 return EFI_INVALID_PARAMETER
;
2850 if (VariableName
[0] == 0) {
2851 return EFI_NOT_FOUND
;
2854 AcquireLockOnlyAtBootTime(&mVariableModuleGlobal
->VariableGlobal
.VariableServicesLock
);
2856 Status
= FindVariable (VariableName
, VendorGuid
, &Variable
, &mVariableModuleGlobal
->VariableGlobal
, FALSE
);
2857 if (Variable
.CurrPtr
== NULL
|| EFI_ERROR (Status
)) {
2864 VarDataSize
= DataSizeOfVariable (Variable
.CurrPtr
);
2865 ASSERT (VarDataSize
!= 0);
2867 if (*DataSize
>= VarDataSize
) {
2869 Status
= EFI_INVALID_PARAMETER
;
2873 CopyMem (Data
, GetVariableDataPtr (Variable
.CurrPtr
), VarDataSize
);
2874 if (Attributes
!= NULL
) {
2875 *Attributes
= Variable
.CurrPtr
->Attributes
;
2878 *DataSize
= VarDataSize
;
2879 UpdateVariableInfo (VariableName
, VendorGuid
, Variable
.Volatile
, TRUE
, FALSE
, FALSE
, FALSE
);
2881 Status
= EFI_SUCCESS
;
2884 *DataSize
= VarDataSize
;
2885 Status
= EFI_BUFFER_TOO_SMALL
;
2890 ReleaseLockOnlyAtBootTime (&mVariableModuleGlobal
->VariableGlobal
.VariableServicesLock
);
2895 This code Finds the Next available variable.
2897 Caution: This function may receive untrusted input.
2898 This function may be invoked in SMM mode. This function will do basic validation, before parse the data.
2900 @param[in] VariableName Pointer to variable name.
2901 @param[in] VendorGuid Variable Vendor Guid.
2902 @param[out] VariablePtr Pointer to variable header address.
2904 @retval EFI_SUCCESS The function completed successfully.
2905 @retval EFI_NOT_FOUND The next variable was not found.
2906 @retval EFI_INVALID_PARAMETER If VariableName is not an empty string, while VendorGuid is NULL.
2907 @retval EFI_INVALID_PARAMETER The input values of VariableName and VendorGuid are not a name and
2908 GUID of an existing variable.
2913 VariableServiceGetNextVariableInternal (
2914 IN CHAR16
*VariableName
,
2915 IN EFI_GUID
*VendorGuid
,
2916 OUT VARIABLE_HEADER
**VariablePtr
2919 VARIABLE_STORE_TYPE Type
;
2920 VARIABLE_POINTER_TRACK Variable
;
2921 VARIABLE_POINTER_TRACK VariableInHob
;
2922 VARIABLE_POINTER_TRACK VariablePtrTrack
;
2924 VARIABLE_STORE_HEADER
*VariableStoreHeader
[VariableStoreTypeMax
];
2926 Status
= FindVariable (VariableName
, VendorGuid
, &Variable
, &mVariableModuleGlobal
->VariableGlobal
, FALSE
);
2927 if (Variable
.CurrPtr
== NULL
|| EFI_ERROR (Status
)) {
2929 // For VariableName is an empty string, FindVariable() will try to find and return
2930 // the first qualified variable, and if FindVariable() returns error (EFI_NOT_FOUND)
2931 // as no any variable is found, still go to return the error (EFI_NOT_FOUND).
2933 if (VariableName
[0] != 0) {
2935 // For VariableName is not an empty string, and FindVariable() returns error as
2936 // VariableName and VendorGuid are not a name and GUID of an existing variable,
2937 // there is no way to get next variable, follow spec to return EFI_INVALID_PARAMETER.
2939 Status
= EFI_INVALID_PARAMETER
;
2944 if (VariableName
[0] != 0) {
2946 // If variable name is not NULL, get next variable.
2948 Variable
.CurrPtr
= GetNextVariablePtr (Variable
.CurrPtr
);
2952 // 0: Volatile, 1: HOB, 2: Non-Volatile.
2953 // The index and attributes mapping must be kept in this order as FindVariable
2954 // makes use of this mapping to implement search algorithm.
2956 VariableStoreHeader
[VariableStoreTypeVolatile
] = (VARIABLE_STORE_HEADER
*) (UINTN
) mVariableModuleGlobal
->VariableGlobal
.VolatileVariableBase
;
2957 VariableStoreHeader
[VariableStoreTypeHob
] = (VARIABLE_STORE_HEADER
*) (UINTN
) mVariableModuleGlobal
->VariableGlobal
.HobVariableBase
;
2958 VariableStoreHeader
[VariableStoreTypeNv
] = mNvVariableCache
;
2962 // Switch from Volatile to HOB, to Non-Volatile.
2964 while (!IsValidVariableHeader (Variable
.CurrPtr
, Variable
.EndPtr
)) {
2966 // Find current storage index
2968 for (Type
= (VARIABLE_STORE_TYPE
) 0; Type
< VariableStoreTypeMax
; Type
++) {
2969 if ((VariableStoreHeader
[Type
] != NULL
) && (Variable
.StartPtr
== GetStartPointer (VariableStoreHeader
[Type
]))) {
2973 ASSERT (Type
< VariableStoreTypeMax
);
2975 // Switch to next storage
2977 for (Type
++; Type
< VariableStoreTypeMax
; Type
++) {
2978 if (VariableStoreHeader
[Type
] != NULL
) {
2983 // Capture the case that
2984 // 1. current storage is the last one, or
2985 // 2. no further storage
2987 if (Type
== VariableStoreTypeMax
) {
2988 Status
= EFI_NOT_FOUND
;
2991 Variable
.StartPtr
= GetStartPointer (VariableStoreHeader
[Type
]);
2992 Variable
.EndPtr
= GetEndPointer (VariableStoreHeader
[Type
]);
2993 Variable
.CurrPtr
= Variable
.StartPtr
;
2997 // Variable is found
2999 if (Variable
.CurrPtr
->State
== VAR_ADDED
|| Variable
.CurrPtr
->State
== (VAR_IN_DELETED_TRANSITION
& VAR_ADDED
)) {
3000 if (!AtRuntime () || ((Variable
.CurrPtr
->Attributes
& EFI_VARIABLE_RUNTIME_ACCESS
) != 0)) {
3001 if (Variable
.CurrPtr
->State
== (VAR_IN_DELETED_TRANSITION
& VAR_ADDED
)) {
3003 // If it is a IN_DELETED_TRANSITION variable,
3004 // and there is also a same ADDED one at the same time,
3007 VariablePtrTrack
.StartPtr
= Variable
.StartPtr
;
3008 VariablePtrTrack
.EndPtr
= Variable
.EndPtr
;
3009 Status
= FindVariableEx (
3010 GetVariableNamePtr (Variable
.CurrPtr
),
3011 GetVendorGuidPtr (Variable
.CurrPtr
),
3015 if (!EFI_ERROR (Status
) && VariablePtrTrack
.CurrPtr
->State
== VAR_ADDED
) {
3016 Variable
.CurrPtr
= GetNextVariablePtr (Variable
.CurrPtr
);
3022 // Don't return NV variable when HOB overrides it
3024 if ((VariableStoreHeader
[VariableStoreTypeHob
] != NULL
) && (VariableStoreHeader
[VariableStoreTypeNv
] != NULL
) &&
3025 (Variable
.StartPtr
== GetStartPointer (VariableStoreHeader
[VariableStoreTypeNv
]))
3027 VariableInHob
.StartPtr
= GetStartPointer (VariableStoreHeader
[VariableStoreTypeHob
]);
3028 VariableInHob
.EndPtr
= GetEndPointer (VariableStoreHeader
[VariableStoreTypeHob
]);
3029 Status
= FindVariableEx (
3030 GetVariableNamePtr (Variable
.CurrPtr
),
3031 GetVendorGuidPtr (Variable
.CurrPtr
),
3035 if (!EFI_ERROR (Status
)) {
3036 Variable
.CurrPtr
= GetNextVariablePtr (Variable
.CurrPtr
);
3041 *VariablePtr
= Variable
.CurrPtr
;
3042 Status
= EFI_SUCCESS
;
3047 Variable
.CurrPtr
= GetNextVariablePtr (Variable
.CurrPtr
);
3056 This code Finds the Next available variable.
3058 Caution: This function may receive untrusted input.
3059 This function may be invoked in SMM mode. This function will do basic validation, before parse the data.
3061 @param VariableNameSize The size of the VariableName buffer. The size must be large
3062 enough to fit input string supplied in VariableName buffer.
3063 @param VariableName Pointer to variable name.
3064 @param VendorGuid Variable Vendor Guid.
3066 @retval EFI_SUCCESS The function completed successfully.
3067 @retval EFI_NOT_FOUND The next variable was not found.
3068 @retval EFI_BUFFER_TOO_SMALL The VariableNameSize is too small for the result.
3069 VariableNameSize has been updated with the size needed to complete the request.
3070 @retval EFI_INVALID_PARAMETER VariableNameSize is NULL.
3071 @retval EFI_INVALID_PARAMETER VariableName is NULL.
3072 @retval EFI_INVALID_PARAMETER VendorGuid is NULL.
3073 @retval EFI_INVALID_PARAMETER The input values of VariableName and VendorGuid are not a name and
3074 GUID of an existing variable.
3075 @retval EFI_INVALID_PARAMETER Null-terminator is not found in the first VariableNameSize bytes of
3076 the input VariableName buffer.
3081 VariableServiceGetNextVariableName (
3082 IN OUT UINTN
*VariableNameSize
,
3083 IN OUT CHAR16
*VariableName
,
3084 IN OUT EFI_GUID
*VendorGuid
3090 VARIABLE_HEADER
*VariablePtr
;
3092 if (VariableNameSize
== NULL
|| VariableName
== NULL
|| VendorGuid
== NULL
) {
3093 return EFI_INVALID_PARAMETER
;
3097 // Calculate the possible maximum length of name string, including the Null terminator.
3099 MaxLen
= *VariableNameSize
/ sizeof (CHAR16
);
3100 if ((MaxLen
== 0) || (StrnLenS (VariableName
, MaxLen
) == MaxLen
)) {
3102 // Null-terminator is not found in the first VariableNameSize bytes of the input VariableName buffer,
3103 // follow spec to return EFI_INVALID_PARAMETER.
3105 return EFI_INVALID_PARAMETER
;
3108 AcquireLockOnlyAtBootTime(&mVariableModuleGlobal
->VariableGlobal
.VariableServicesLock
);
3110 Status
= VariableServiceGetNextVariableInternal (VariableName
, VendorGuid
, &VariablePtr
);
3111 if (!EFI_ERROR (Status
)) {
3112 VarNameSize
= NameSizeOfVariable (VariablePtr
);
3113 ASSERT (VarNameSize
!= 0);
3114 if (VarNameSize
<= *VariableNameSize
) {
3115 CopyMem (VariableName
, GetVariableNamePtr (VariablePtr
), VarNameSize
);
3116 CopyMem (VendorGuid
, GetVendorGuidPtr (VariablePtr
), sizeof (EFI_GUID
));
3117 Status
= EFI_SUCCESS
;
3119 Status
= EFI_BUFFER_TOO_SMALL
;
3122 *VariableNameSize
= VarNameSize
;
3125 ReleaseLockOnlyAtBootTime (&mVariableModuleGlobal
->VariableGlobal
.VariableServicesLock
);
3131 This code sets variable in storage blocks (Volatile or Non-Volatile).
3133 Caution: This function may receive untrusted input.
3134 This function may be invoked in SMM mode, and datasize and data are external input.
3135 This function will do basic validation, before parse the data.
3136 This function will parse the authentication carefully to avoid security issues, like
3137 buffer overflow, integer overflow.
3138 This function will check attribute carefully to avoid authentication bypass.
3140 @param VariableName Name of Variable to be found.
3141 @param VendorGuid Variable vendor GUID.
3142 @param Attributes Attribute value of the variable found
3143 @param DataSize Size of Data found. If size is less than the
3144 data, this value contains the required size.
3145 @param Data Data pointer.
3147 @return EFI_INVALID_PARAMETER Invalid parameter.
3148 @return EFI_SUCCESS Set successfully.
3149 @return EFI_OUT_OF_RESOURCES Resource not enough to set variable.
3150 @return EFI_NOT_FOUND Not found.
3151 @return EFI_WRITE_PROTECTED Variable is read-only.
3156 VariableServiceSetVariable (
3157 IN CHAR16
*VariableName
,
3158 IN EFI_GUID
*VendorGuid
,
3159 IN UINT32 Attributes
,
3164 VARIABLE_POINTER_TRACK Variable
;
3166 VARIABLE_HEADER
*NextVariable
;
3167 EFI_PHYSICAL_ADDRESS Point
;
3171 // Check input parameters.
3173 if (VariableName
== NULL
|| VariableName
[0] == 0 || VendorGuid
== NULL
) {
3174 return EFI_INVALID_PARAMETER
;
3177 if (DataSize
!= 0 && Data
== NULL
) {
3178 return EFI_INVALID_PARAMETER
;
3182 // Check for reserverd bit in variable attribute.
3183 // EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS is deprecated but we still allow
3184 // the delete operation of common authenticated variable at user physical presence.
3185 // So leave EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS attribute check to AuthVariableLib
3187 if ((Attributes
& (~(EFI_VARIABLE_ATTRIBUTES_MASK
| EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS
))) != 0) {
3188 return EFI_INVALID_PARAMETER
;
3192 // Make sure if runtime bit is set, boot service bit is set also.
3194 if ((Attributes
& (EFI_VARIABLE_RUNTIME_ACCESS
| EFI_VARIABLE_BOOTSERVICE_ACCESS
)) == EFI_VARIABLE_RUNTIME_ACCESS
) {
3195 if ((Attributes
& EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS
) != 0) {
3196 return EFI_UNSUPPORTED
;
3198 return EFI_INVALID_PARAMETER
;
3200 } else if ((Attributes
& VARIABLE_ATTRIBUTE_AT_AW
) != 0) {
3201 if (!mVariableModuleGlobal
->VariableGlobal
.AuthSupport
) {
3203 // Not support authenticated variable write.
3205 return EFI_INVALID_PARAMETER
;
3207 } else if ((Attributes
& EFI_VARIABLE_HARDWARE_ERROR_RECORD
) != 0) {
3208 if (PcdGet32 (PcdHwErrStorageSize
) == 0) {
3210 // Not support harware error record variable variable.
3212 return EFI_INVALID_PARAMETER
;
3217 // EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS and EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS attribute
3218 // cannot be set both.
3220 if (((Attributes
& EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS
) == EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS
)
3221 && ((Attributes
& EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS
) == EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS
)) {
3222 return EFI_UNSUPPORTED
;
3225 if ((Attributes
& EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS
) == EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS
) {
3227 // If DataSize == AUTHINFO_SIZE and then PayloadSize is 0.
3228 // Maybe it's the delete operation of common authenticated variable at user physical presence.
3230 if (DataSize
!= AUTHINFO_SIZE
) {
3231 return EFI_UNSUPPORTED
;
3233 PayloadSize
= DataSize
- AUTHINFO_SIZE
;
3234 } else if ((Attributes
& EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS
) == EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS
) {
3236 // Sanity check for EFI_VARIABLE_AUTHENTICATION_2 descriptor.
3238 if (DataSize
< OFFSET_OF_AUTHINFO2_CERT_DATA
||
3239 ((EFI_VARIABLE_AUTHENTICATION_2
*) Data
)->AuthInfo
.Hdr
.dwLength
> DataSize
- (OFFSET_OF (EFI_VARIABLE_AUTHENTICATION_2
, AuthInfo
)) ||
3240 ((EFI_VARIABLE_AUTHENTICATION_2
*) Data
)->AuthInfo
.Hdr
.dwLength
< OFFSET_OF (WIN_CERTIFICATE_UEFI_GUID
, CertData
)) {
3241 return EFI_SECURITY_VIOLATION
;
3244 // The VariableSpeculationBarrier() call here is to ensure the above sanity
3245 // check for the EFI_VARIABLE_AUTHENTICATION_2 descriptor has been completed
3246 // before the execution of subsequent codes.
3248 VariableSpeculationBarrier ();
3249 PayloadSize
= DataSize
- AUTHINFO2_SIZE (Data
);
3251 PayloadSize
= DataSize
;
3254 if ((UINTN
)(~0) - PayloadSize
< StrSize(VariableName
)){
3256 // Prevent whole variable size overflow
3258 return EFI_INVALID_PARAMETER
;
3262 // The size of the VariableName, including the Unicode Null in bytes plus
3263 // the DataSize is limited to maximum size of PcdGet32 (PcdMaxHardwareErrorVariableSize)
3264 // bytes for HwErrRec#### variable.
3266 if ((Attributes
& EFI_VARIABLE_HARDWARE_ERROR_RECORD
) == EFI_VARIABLE_HARDWARE_ERROR_RECORD
) {
3267 if (StrSize (VariableName
) + PayloadSize
> PcdGet32 (PcdMaxHardwareErrorVariableSize
) - GetVariableHeaderSize ()) {
3268 return EFI_INVALID_PARAMETER
;
3272 // The size of the VariableName, including the Unicode Null in bytes plus
3273 // the DataSize is limited to maximum size of Max(Auth|Volatile)VariableSize bytes.
3275 if ((Attributes
& VARIABLE_ATTRIBUTE_AT_AW
) != 0) {
3276 if (StrSize (VariableName
) + PayloadSize
> mVariableModuleGlobal
->MaxAuthVariableSize
- GetVariableHeaderSize ()) {
3277 DEBUG ((DEBUG_ERROR
,
3278 "%a: Failed to set variable '%s' with Guid %g\n",
3279 __FUNCTION__
, VariableName
, VendorGuid
));
3280 DEBUG ((DEBUG_ERROR
,
3281 "NameSize(0x%x) + PayloadSize(0x%x) > "
3282 "MaxAuthVariableSize(0x%x) - HeaderSize(0x%x)\n",
3283 StrSize (VariableName
), PayloadSize
,
3284 mVariableModuleGlobal
->MaxAuthVariableSize
,
3285 GetVariableHeaderSize ()
3287 return EFI_INVALID_PARAMETER
;
3289 } else if ((Attributes
& EFI_VARIABLE_NON_VOLATILE
) != 0) {
3290 if (StrSize (VariableName
) + PayloadSize
> mVariableModuleGlobal
->MaxVariableSize
- GetVariableHeaderSize ()) {
3291 DEBUG ((DEBUG_ERROR
,
3292 "%a: Failed to set variable '%s' with Guid %g\n",
3293 __FUNCTION__
, VariableName
, VendorGuid
));
3294 DEBUG ((DEBUG_ERROR
,
3295 "NameSize(0x%x) + PayloadSize(0x%x) > "
3296 "MaxVariableSize(0x%x) - HeaderSize(0x%x)\n",
3297 StrSize (VariableName
), PayloadSize
,
3298 mVariableModuleGlobal
->MaxVariableSize
,
3299 GetVariableHeaderSize ()
3301 return EFI_INVALID_PARAMETER
;
3304 if (StrSize (VariableName
) + PayloadSize
> mVariableModuleGlobal
->MaxVolatileVariableSize
- GetVariableHeaderSize ()) {
3305 DEBUG ((DEBUG_ERROR
,
3306 "%a: Failed to set variable '%s' with Guid %g\n",
3307 __FUNCTION__
, VariableName
, VendorGuid
));
3308 DEBUG ((DEBUG_ERROR
,
3309 "NameSize(0x%x) + PayloadSize(0x%x) > "
3310 "MaxVolatileVariableSize(0x%x) - HeaderSize(0x%x)\n",
3311 StrSize (VariableName
), PayloadSize
,
3312 mVariableModuleGlobal
->MaxVolatileVariableSize
,
3313 GetVariableHeaderSize ()
3315 return EFI_INVALID_PARAMETER
;
3321 // Special Handling for MOR Lock variable.
3323 Status
= SetVariableCheckHandlerMor (VariableName
, VendorGuid
, Attributes
, PayloadSize
, (VOID
*) ((UINTN
) Data
+ DataSize
- PayloadSize
));
3324 if (Status
== EFI_ALREADY_STARTED
) {
3326 // EFI_ALREADY_STARTED means the SetVariable() action is handled inside of SetVariableCheckHandlerMor().
3327 // Variable driver can just return SUCCESS.
3331 if (EFI_ERROR (Status
)) {
3335 Status
= VarCheckLibSetVariableCheck (VariableName
, VendorGuid
, Attributes
, PayloadSize
, (VOID
*) ((UINTN
) Data
+ DataSize
- PayloadSize
), mRequestSource
);
3336 if (EFI_ERROR (Status
)) {
3340 AcquireLockOnlyAtBootTime(&mVariableModuleGlobal
->VariableGlobal
.VariableServicesLock
);
3343 // Consider reentrant in MCA/INIT/NMI. It needs be reupdated.
3345 if (1 < InterlockedIncrement (&mVariableModuleGlobal
->VariableGlobal
.ReentrantState
)) {
3346 Point
= mVariableModuleGlobal
->VariableGlobal
.NonVolatileVariableBase
;
3348 // Parse non-volatile variable data and get last variable offset.
3350 NextVariable
= GetStartPointer ((VARIABLE_STORE_HEADER
*) (UINTN
) Point
);
3351 while (IsValidVariableHeader (NextVariable
, GetEndPointer ((VARIABLE_STORE_HEADER
*) (UINTN
) Point
))) {
3352 NextVariable
= GetNextVariablePtr (NextVariable
);
3354 mVariableModuleGlobal
->NonVolatileLastVariableOffset
= (UINTN
) NextVariable
- (UINTN
) Point
;
3358 // Check whether the input variable is already existed.
3360 Status
= FindVariable (VariableName
, VendorGuid
, &Variable
, &mVariableModuleGlobal
->VariableGlobal
, TRUE
);
3361 if (!EFI_ERROR (Status
)) {
3362 if (((Variable
.CurrPtr
->Attributes
& EFI_VARIABLE_RUNTIME_ACCESS
) == 0) && AtRuntime ()) {
3363 Status
= EFI_WRITE_PROTECTED
;
3366 if (Attributes
!= 0 && (Attributes
& (~EFI_VARIABLE_APPEND_WRITE
)) != Variable
.CurrPtr
->Attributes
) {
3368 // If a preexisting variable is rewritten with different attributes, SetVariable() shall not
3369 // modify the variable and shall return EFI_INVALID_PARAMETER. Two exceptions to this rule:
3370 // 1. No access attributes specified
3371 // 2. The only attribute differing is EFI_VARIABLE_APPEND_WRITE
3373 Status
= EFI_INVALID_PARAMETER
;
3374 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
));
3379 if (!FeaturePcdGet (PcdUefiVariableDefaultLangDeprecate
)) {
3381 // Hook the operation of setting PlatformLangCodes/PlatformLang and LangCodes/Lang.
3383 Status
= AutoUpdateLangVariable (VariableName
, Data
, DataSize
);
3384 if (EFI_ERROR (Status
)) {
3386 // The auto update operation failed, directly return to avoid inconsistency between PlatformLang and Lang.
3392 if (mVariableModuleGlobal
->VariableGlobal
.AuthSupport
) {
3393 Status
= AuthVariableLibProcessVariable (VariableName
, VendorGuid
, Data
, DataSize
, Attributes
);
3395 Status
= UpdateVariable (VariableName
, VendorGuid
, Data
, DataSize
, Attributes
, 0, 0, &Variable
, NULL
);
3399 InterlockedDecrement (&mVariableModuleGlobal
->VariableGlobal
.ReentrantState
);
3400 ReleaseLockOnlyAtBootTime (&mVariableModuleGlobal
->VariableGlobal
.VariableServicesLock
);
3402 if (!AtRuntime ()) {
3403 if (!EFI_ERROR (Status
)) {
3416 This code returns information about the EFI variables.
3418 Caution: This function may receive untrusted input.
3419 This function may be invoked in SMM mode. This function will do basic validation, before parse the data.
3421 @param Attributes Attributes bitmask to specify the type of variables
3422 on which to return information.
3423 @param MaximumVariableStorageSize Pointer to the maximum size of the storage space available
3424 for the EFI variables associated with the attributes specified.
3425 @param RemainingVariableStorageSize Pointer to the remaining size of the storage space available
3426 for EFI variables associated with the attributes specified.
3427 @param MaximumVariableSize Pointer to the maximum size of an individual EFI variables
3428 associated with the attributes specified.
3430 @return EFI_SUCCESS Query successfully.
3435 VariableServiceQueryVariableInfoInternal (
3436 IN UINT32 Attributes
,
3437 OUT UINT64
*MaximumVariableStorageSize
,
3438 OUT UINT64
*RemainingVariableStorageSize
,
3439 OUT UINT64
*MaximumVariableSize
3442 VARIABLE_HEADER
*Variable
;
3443 VARIABLE_HEADER
*NextVariable
;
3444 UINT64 VariableSize
;
3445 VARIABLE_STORE_HEADER
*VariableStoreHeader
;
3446 UINT64 CommonVariableTotalSize
;
3447 UINT64 HwErrVariableTotalSize
;
3449 VARIABLE_POINTER_TRACK VariablePtrTrack
;
3451 CommonVariableTotalSize
= 0;
3452 HwErrVariableTotalSize
= 0;
3454 if((Attributes
& EFI_VARIABLE_NON_VOLATILE
) == 0) {
3456 // Query is Volatile related.
3458 VariableStoreHeader
= (VARIABLE_STORE_HEADER
*) ((UINTN
) mVariableModuleGlobal
->VariableGlobal
.VolatileVariableBase
);
3461 // Query is Non-Volatile related.
3463 VariableStoreHeader
= mNvVariableCache
;
3467 // Now let's fill *MaximumVariableStorageSize *RemainingVariableStorageSize
3468 // with the storage size (excluding the storage header size).
3470 *MaximumVariableStorageSize
= VariableStoreHeader
->Size
- sizeof (VARIABLE_STORE_HEADER
);
3473 // Harware error record variable needs larger size.
3475 if ((Attributes
& (EFI_VARIABLE_NON_VOLATILE
| EFI_VARIABLE_HARDWARE_ERROR_RECORD
)) == (EFI_VARIABLE_NON_VOLATILE
| EFI_VARIABLE_HARDWARE_ERROR_RECORD
)) {
3476 *MaximumVariableStorageSize
= PcdGet32 (PcdHwErrStorageSize
);
3477 *MaximumVariableSize
= PcdGet32 (PcdMaxHardwareErrorVariableSize
) - GetVariableHeaderSize ();
3479 if ((Attributes
& EFI_VARIABLE_NON_VOLATILE
) != 0) {
3481 *MaximumVariableStorageSize
= mVariableModuleGlobal
->CommonRuntimeVariableSpace
;
3483 *MaximumVariableStorageSize
= mVariableModuleGlobal
->CommonVariableSpace
;
3488 // Let *MaximumVariableSize be Max(Auth|Volatile)VariableSize with the exception of the variable header size.
3490 if ((Attributes
& VARIABLE_ATTRIBUTE_AT_AW
) != 0) {
3491 *MaximumVariableSize
= mVariableModuleGlobal
->MaxAuthVariableSize
- GetVariableHeaderSize ();
3492 } else if ((Attributes
& EFI_VARIABLE_NON_VOLATILE
) != 0) {
3493 *MaximumVariableSize
= mVariableModuleGlobal
->MaxVariableSize
- GetVariableHeaderSize ();
3495 *MaximumVariableSize
= mVariableModuleGlobal
->MaxVolatileVariableSize
- GetVariableHeaderSize ();
3500 // Point to the starting address of the variables.
3502 Variable
= GetStartPointer (VariableStoreHeader
);
3505 // Now walk through the related variable store.
3507 while (IsValidVariableHeader (Variable
, GetEndPointer (VariableStoreHeader
))) {
3508 NextVariable
= GetNextVariablePtr (Variable
);
3509 VariableSize
= (UINT64
) (UINTN
) NextVariable
- (UINT64
) (UINTN
) Variable
;
3513 // We don't take the state of the variables in mind
3514 // when calculating RemainingVariableStorageSize,
3515 // since the space occupied by variables not marked with
3516 // VAR_ADDED is not allowed to be reclaimed in Runtime.
3518 if ((Variable
->Attributes
& EFI_VARIABLE_HARDWARE_ERROR_RECORD
) == EFI_VARIABLE_HARDWARE_ERROR_RECORD
) {
3519 HwErrVariableTotalSize
+= VariableSize
;
3521 CommonVariableTotalSize
+= VariableSize
;
3525 // Only care about Variables with State VAR_ADDED, because
3526 // the space not marked as VAR_ADDED is reclaimable now.
3528 if (Variable
->State
== VAR_ADDED
) {
3529 if ((Variable
->Attributes
& EFI_VARIABLE_HARDWARE_ERROR_RECORD
) == EFI_VARIABLE_HARDWARE_ERROR_RECORD
) {
3530 HwErrVariableTotalSize
+= VariableSize
;
3532 CommonVariableTotalSize
+= VariableSize
;
3534 } else if (Variable
->State
== (VAR_IN_DELETED_TRANSITION
& VAR_ADDED
)) {
3536 // If it is a IN_DELETED_TRANSITION variable,
3537 // and there is not also a same ADDED one at the same time,
3538 // this IN_DELETED_TRANSITION variable is valid.
3540 VariablePtrTrack
.StartPtr
= GetStartPointer (VariableStoreHeader
);
3541 VariablePtrTrack
.EndPtr
= GetEndPointer (VariableStoreHeader
);
3542 Status
= FindVariableEx (
3543 GetVariableNamePtr (Variable
),
3544 GetVendorGuidPtr (Variable
),
3548 if (!EFI_ERROR (Status
) && VariablePtrTrack
.CurrPtr
->State
!= VAR_ADDED
) {
3549 if ((Variable
->Attributes
& EFI_VARIABLE_HARDWARE_ERROR_RECORD
) == EFI_VARIABLE_HARDWARE_ERROR_RECORD
) {
3550 HwErrVariableTotalSize
+= VariableSize
;
3552 CommonVariableTotalSize
+= VariableSize
;
3559 // Go to the next one.
3561 Variable
= NextVariable
;
3564 if ((Attributes
& EFI_VARIABLE_HARDWARE_ERROR_RECORD
) == EFI_VARIABLE_HARDWARE_ERROR_RECORD
){
3565 *RemainingVariableStorageSize
= *MaximumVariableStorageSize
- HwErrVariableTotalSize
;
3567 if (*MaximumVariableStorageSize
< CommonVariableTotalSize
) {
3568 *RemainingVariableStorageSize
= 0;
3570 *RemainingVariableStorageSize
= *MaximumVariableStorageSize
- CommonVariableTotalSize
;
3574 if (*RemainingVariableStorageSize
< GetVariableHeaderSize ()) {
3575 *MaximumVariableSize
= 0;
3576 } else if ((*RemainingVariableStorageSize
- GetVariableHeaderSize ()) < *MaximumVariableSize
) {
3577 *MaximumVariableSize
= *RemainingVariableStorageSize
- GetVariableHeaderSize ();
3585 This code returns information about the EFI variables.
3587 Caution: This function may receive untrusted input.
3588 This function may be invoked in SMM mode. This function will do basic validation, before parse the data.
3590 @param Attributes Attributes bitmask to specify the type of variables
3591 on which to return information.
3592 @param MaximumVariableStorageSize Pointer to the maximum size of the storage space available
3593 for the EFI variables associated with the attributes specified.
3594 @param RemainingVariableStorageSize Pointer to the remaining size of the storage space available
3595 for EFI variables associated with the attributes specified.
3596 @param MaximumVariableSize Pointer to the maximum size of an individual EFI variables
3597 associated with the attributes specified.
3599 @return EFI_INVALID_PARAMETER An invalid combination of attribute bits was supplied.
3600 @return EFI_SUCCESS Query successfully.
3601 @return EFI_UNSUPPORTED The attribute is not supported on this platform.
3606 VariableServiceQueryVariableInfo (
3607 IN UINT32 Attributes
,
3608 OUT UINT64
*MaximumVariableStorageSize
,
3609 OUT UINT64
*RemainingVariableStorageSize
,
3610 OUT UINT64
*MaximumVariableSize
3615 if(MaximumVariableStorageSize
== NULL
|| RemainingVariableStorageSize
== NULL
|| MaximumVariableSize
== NULL
|| Attributes
== 0) {
3616 return EFI_INVALID_PARAMETER
;
3619 if ((Attributes
& EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS
) != 0) {
3621 // Deprecated attribute, make this check as highest priority.
3623 return EFI_UNSUPPORTED
;
3626 if ((Attributes
& EFI_VARIABLE_ATTRIBUTES_MASK
) == 0) {
3628 // Make sure the Attributes combination is supported by the platform.
3630 return EFI_UNSUPPORTED
;
3631 } else if ((Attributes
& (EFI_VARIABLE_RUNTIME_ACCESS
| EFI_VARIABLE_BOOTSERVICE_ACCESS
)) == EFI_VARIABLE_RUNTIME_ACCESS
) {
3633 // Make sure if runtime bit is set, boot service bit is set also.
3635 return EFI_INVALID_PARAMETER
;
3636 } else if (AtRuntime () && ((Attributes
& EFI_VARIABLE_RUNTIME_ACCESS
) == 0)) {
3638 // Make sure RT Attribute is set if we are in Runtime phase.
3640 return EFI_INVALID_PARAMETER
;
3641 } else if ((Attributes
& (EFI_VARIABLE_NON_VOLATILE
| EFI_VARIABLE_HARDWARE_ERROR_RECORD
)) == EFI_VARIABLE_HARDWARE_ERROR_RECORD
) {
3643 // Make sure Hw Attribute is set with NV.
3645 return EFI_INVALID_PARAMETER
;
3646 } else if ((Attributes
& VARIABLE_ATTRIBUTE_AT_AW
) != 0) {
3647 if (!mVariableModuleGlobal
->VariableGlobal
.AuthSupport
) {
3649 // Not support authenticated variable write.
3651 return EFI_UNSUPPORTED
;
3653 } else if ((Attributes
& EFI_VARIABLE_HARDWARE_ERROR_RECORD
) != 0) {
3654 if (PcdGet32 (PcdHwErrStorageSize
) == 0) {
3656 // Not support harware error record variable variable.
3658 return EFI_UNSUPPORTED
;
3662 AcquireLockOnlyAtBootTime(&mVariableModuleGlobal
->VariableGlobal
.VariableServicesLock
);
3664 Status
= VariableServiceQueryVariableInfoInternal (
3666 MaximumVariableStorageSize
,
3667 RemainingVariableStorageSize
,
3671 ReleaseLockOnlyAtBootTime (&mVariableModuleGlobal
->VariableGlobal
.VariableServicesLock
);
3676 This function reclaims variable storage if free size is below the threshold.
3678 Caution: This function may be invoked at SMM mode.
3679 Care must be taken to make sure not security issue.
3688 UINTN RemainingCommonRuntimeVariableSpace
;
3689 UINTN RemainingHwErrVariableSpace
;
3690 STATIC BOOLEAN Reclaimed
;
3693 // This function will be called only once at EndOfDxe or ReadyToBoot event.
3700 Status
= EFI_SUCCESS
;
3702 if (mVariableModuleGlobal
->CommonRuntimeVariableSpace
< mVariableModuleGlobal
->CommonVariableTotalSize
) {
3703 RemainingCommonRuntimeVariableSpace
= 0;
3705 RemainingCommonRuntimeVariableSpace
= mVariableModuleGlobal
->CommonRuntimeVariableSpace
- mVariableModuleGlobal
->CommonVariableTotalSize
;
3708 RemainingHwErrVariableSpace
= PcdGet32 (PcdHwErrStorageSize
) - mVariableModuleGlobal
->HwErrVariableTotalSize
;
3711 // Check if the free area is below a threshold.
3713 if (((RemainingCommonRuntimeVariableSpace
< mVariableModuleGlobal
->MaxVariableSize
) ||
3714 (RemainingCommonRuntimeVariableSpace
< mVariableModuleGlobal
->MaxAuthVariableSize
)) ||
3715 ((PcdGet32 (PcdHwErrStorageSize
) != 0) &&
3716 (RemainingHwErrVariableSpace
< PcdGet32 (PcdMaxHardwareErrorVariableSize
)))){
3718 mVariableModuleGlobal
->VariableGlobal
.NonVolatileVariableBase
,
3719 &mVariableModuleGlobal
->NonVolatileLastVariableOffset
,
3725 ASSERT_EFI_ERROR (Status
);
3730 Get non-volatile maximum variable size.
3732 @return Non-volatile maximum variable size.
3736 GetNonVolatileMaxVariableSize (
3740 if (PcdGet32 (PcdHwErrStorageSize
) != 0) {
3741 return MAX (MAX (PcdGet32 (PcdMaxVariableSize
), PcdGet32 (PcdMaxAuthVariableSize
)),
3742 PcdGet32 (PcdMaxHardwareErrorVariableSize
));
3744 return MAX (PcdGet32 (PcdMaxVariableSize
), PcdGet32 (PcdMaxAuthVariableSize
));
3749 Get maximum variable size, covering both non-volatile and volatile variables.
3751 @return Maximum variable size.
3755 GetMaxVariableSize (
3759 UINTN MaxVariableSize
;
3761 MaxVariableSize
= GetNonVolatileMaxVariableSize();
3763 // The condition below fails implicitly if PcdMaxVolatileVariableSize equals
3764 // the default zero value.
3766 if (MaxVariableSize
< PcdGet32 (PcdMaxVolatileVariableSize
)) {
3767 MaxVariableSize
= PcdGet32 (PcdMaxVolatileVariableSize
);
3769 return MaxVariableSize
;
3773 Init real non-volatile variable store.
3775 @param[out] VariableStoreBase Output pointer to real non-volatile variable store base.
3777 @retval EFI_SUCCESS Function successfully executed.
3778 @retval EFI_OUT_OF_RESOURCES Fail to allocate enough memory resource.
3779 @retval EFI_VOLUME_CORRUPTED Variable Store or Firmware Volume for Variable Store is corrupted.
3783 InitRealNonVolatileVariableStore (
3784 OUT EFI_PHYSICAL_ADDRESS
*VariableStoreBase
3787 EFI_FIRMWARE_VOLUME_HEADER
*FvHeader
;
3788 VARIABLE_STORE_HEADER
*VariableStore
;
3789 UINT32 VariableStoreLength
;
3790 EFI_HOB_GUID_TYPE
*GuidHob
;
3791 EFI_PHYSICAL_ADDRESS NvStorageBase
;
3792 UINT8
*NvStorageData
;
3793 UINT32 NvStorageSize
;
3794 FAULT_TOLERANT_WRITE_LAST_WRITE_DATA
*FtwLastWriteData
;
3795 UINT32 BackUpOffset
;
3797 UINT32 HwErrStorageSize
;
3798 UINT32 MaxUserNvVariableSpaceSize
;
3799 UINT32 BoottimeReservedNvVariableSpaceSize
;
3803 mVariableModuleGlobal
->FvbInstance
= NULL
;
3806 // Allocate runtime memory used for a memory copy of the FLASH region.
3807 // Keep the memory and the FLASH in sync as updates occur.
3809 NvStorageSize
= PcdGet32 (PcdFlashNvStorageVariableSize
);
3810 NvStorageData
= AllocateRuntimeZeroPool (NvStorageSize
);
3811 if (NvStorageData
== NULL
) {
3812 return EFI_OUT_OF_RESOURCES
;
3815 NvStorageBase
= NV_STORAGE_VARIABLE_BASE
;
3816 ASSERT (NvStorageBase
!= 0);
3819 // Copy NV storage data to the memory buffer.
3821 CopyMem (NvStorageData
, (UINT8
*) (UINTN
) NvStorageBase
, NvStorageSize
);
3823 Status
= GetFtwProtocol ((VOID
**)&FtwProtocol
);
3825 // If FTW protocol has been installed, no need to check FTW last write data hob.
3827 if (EFI_ERROR (Status
)) {
3829 // Check the FTW last write data hob.
3831 GuidHob
= GetFirstGuidHob (&gEdkiiFaultTolerantWriteGuid
);
3832 if (GuidHob
!= NULL
) {
3833 FtwLastWriteData
= (FAULT_TOLERANT_WRITE_LAST_WRITE_DATA
*) GET_GUID_HOB_DATA (GuidHob
);
3834 if (FtwLastWriteData
->TargetAddress
== NvStorageBase
) {
3835 DEBUG ((EFI_D_INFO
, "Variable: NV storage is backed up in spare block: 0x%x\n", (UINTN
) FtwLastWriteData
->SpareAddress
));
3837 // Copy the backed up NV storage data to the memory buffer from spare block.
3839 CopyMem (NvStorageData
, (UINT8
*) (UINTN
) (FtwLastWriteData
->SpareAddress
), NvStorageSize
);
3840 } else if ((FtwLastWriteData
->TargetAddress
> NvStorageBase
) &&
3841 (FtwLastWriteData
->TargetAddress
< (NvStorageBase
+ NvStorageSize
))) {
3843 // Flash NV storage from the Offset is backed up in spare block.
3845 BackUpOffset
= (UINT32
) (FtwLastWriteData
->TargetAddress
- NvStorageBase
);
3846 BackUpSize
= NvStorageSize
- BackUpOffset
;
3847 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
));
3849 // Copy the partial backed up NV storage data to the memory buffer from spare block.
3851 CopyMem (NvStorageData
+ BackUpOffset
, (UINT8
*) (UINTN
) FtwLastWriteData
->SpareAddress
, BackUpSize
);
3856 FvHeader
= (EFI_FIRMWARE_VOLUME_HEADER
*) NvStorageData
;
3859 // Check if the Firmware Volume is not corrupted
3861 if ((FvHeader
->Signature
!= EFI_FVH_SIGNATURE
) || (!CompareGuid (&gEfiSystemNvDataFvGuid
, &FvHeader
->FileSystemGuid
))) {
3862 FreePool (NvStorageData
);
3863 DEBUG ((EFI_D_ERROR
, "Firmware Volume for Variable Store is corrupted\n"));
3864 return EFI_VOLUME_CORRUPTED
;
3867 VariableStore
= (VARIABLE_STORE_HEADER
*) ((UINTN
) FvHeader
+ FvHeader
->HeaderLength
);
3868 VariableStoreLength
= NvStorageSize
- FvHeader
->HeaderLength
;
3869 ASSERT (sizeof (VARIABLE_STORE_HEADER
) <= VariableStoreLength
);
3870 ASSERT (VariableStore
->Size
== VariableStoreLength
);
3873 // Check if the Variable Store header is not corrupted
3875 if (GetVariableStoreStatus (VariableStore
) != EfiValid
) {
3876 FreePool (NvStorageData
);
3877 DEBUG((EFI_D_ERROR
, "Variable Store header is corrupted\n"));
3878 return EFI_VOLUME_CORRUPTED
;
3881 mNvFvHeaderCache
= FvHeader
;
3883 *VariableStoreBase
= (EFI_PHYSICAL_ADDRESS
) (UINTN
) VariableStore
;
3885 HwErrStorageSize
= PcdGet32 (PcdHwErrStorageSize
);
3886 MaxUserNvVariableSpaceSize
= PcdGet32 (PcdMaxUserNvVariableSpaceSize
);
3887 BoottimeReservedNvVariableSpaceSize
= PcdGet32 (PcdBoottimeReservedNvVariableSpaceSize
);
3890 // Note that in EdkII variable driver implementation, Hardware Error Record type variable
3891 // is stored with common variable in the same NV region. So the platform integrator should
3892 // ensure that the value of PcdHwErrStorageSize is less than the value of
3893 // (VariableStoreLength - sizeof (VARIABLE_STORE_HEADER)).
3895 ASSERT (HwErrStorageSize
< (VariableStoreLength
- sizeof (VARIABLE_STORE_HEADER
)));
3897 // Ensure that the value of PcdMaxUserNvVariableSpaceSize is less than the value of
3898 // (VariableStoreLength - sizeof (VARIABLE_STORE_HEADER)) - PcdGet32 (PcdHwErrStorageSize).
3900 ASSERT (MaxUserNvVariableSpaceSize
< (VariableStoreLength
- sizeof (VARIABLE_STORE_HEADER
) - HwErrStorageSize
));
3902 // Ensure that the value of PcdBoottimeReservedNvVariableSpaceSize is less than the value of
3903 // (VariableStoreLength - sizeof (VARIABLE_STORE_HEADER)) - PcdGet32 (PcdHwErrStorageSize).
3905 ASSERT (BoottimeReservedNvVariableSpaceSize
< (VariableStoreLength
- sizeof (VARIABLE_STORE_HEADER
) - HwErrStorageSize
));
3907 mVariableModuleGlobal
->CommonVariableSpace
= ((UINTN
) VariableStoreLength
- sizeof (VARIABLE_STORE_HEADER
) - HwErrStorageSize
);
3908 mVariableModuleGlobal
->CommonMaxUserVariableSpace
= ((MaxUserNvVariableSpaceSize
!= 0) ? MaxUserNvVariableSpaceSize
: mVariableModuleGlobal
->CommonVariableSpace
);
3909 mVariableModuleGlobal
->CommonRuntimeVariableSpace
= mVariableModuleGlobal
->CommonVariableSpace
- BoottimeReservedNvVariableSpaceSize
;
3911 DEBUG ((EFI_D_INFO
, "Variable driver common space: 0x%x 0x%x 0x%x\n", mVariableModuleGlobal
->CommonVariableSpace
, mVariableModuleGlobal
->CommonMaxUserVariableSpace
, mVariableModuleGlobal
->CommonRuntimeVariableSpace
));
3914 // The max NV variable size should be < (VariableStoreLength - sizeof (VARIABLE_STORE_HEADER)).
3916 ASSERT (GetNonVolatileMaxVariableSize () < (VariableStoreLength
- sizeof (VARIABLE_STORE_HEADER
)));
3922 Init emulated non-volatile variable store.
3924 @param[out] VariableStoreBase Output pointer to emulated non-volatile variable store base.
3926 @retval EFI_SUCCESS Function successfully executed.
3927 @retval EFI_OUT_OF_RESOURCES Fail to allocate enough memory resource.
3931 InitEmuNonVolatileVariableStore (
3932 EFI_PHYSICAL_ADDRESS
*VariableStoreBase
3935 VARIABLE_STORE_HEADER
*VariableStore
;
3936 UINT32 VariableStoreLength
;
3937 BOOLEAN FullyInitializeStore
;
3938 UINT32 HwErrStorageSize
;
3940 FullyInitializeStore
= TRUE
;
3942 VariableStoreLength
= PcdGet32 (PcdVariableStoreSize
);
3943 ASSERT (sizeof (VARIABLE_STORE_HEADER
) <= VariableStoreLength
);
3946 // Allocate memory for variable store.
3948 if (PcdGet64 (PcdEmuVariableNvStoreReserved
) == 0) {
3949 VariableStore
= (VARIABLE_STORE_HEADER
*) AllocateRuntimePool (VariableStoreLength
);
3950 if (VariableStore
== NULL
) {
3951 return EFI_OUT_OF_RESOURCES
;
3955 // A memory location has been reserved for the NV variable store. Certain
3956 // platforms may be able to preserve a memory range across system resets,
3957 // thereby providing better NV variable emulation.
3960 (VARIABLE_STORE_HEADER
*)(VOID
*)(UINTN
)
3961 PcdGet64 (PcdEmuVariableNvStoreReserved
);
3962 if ((VariableStore
->Size
== VariableStoreLength
) &&
3963 (CompareGuid (&VariableStore
->Signature
, &gEfiAuthenticatedVariableGuid
) ||
3964 CompareGuid (&VariableStore
->Signature
, &gEfiVariableGuid
)) &&
3965 (VariableStore
->Format
== VARIABLE_STORE_FORMATTED
) &&
3966 (VariableStore
->State
== VARIABLE_STORE_HEALTHY
)) {
3969 "Variable Store reserved at %p appears to be valid\n",
3972 FullyInitializeStore
= FALSE
;
3976 if (FullyInitializeStore
) {
3977 SetMem (VariableStore
, VariableStoreLength
, 0xff);
3979 // Use gEfiAuthenticatedVariableGuid for potential auth variable support.
3981 CopyGuid (&VariableStore
->Signature
, &gEfiAuthenticatedVariableGuid
);
3982 VariableStore
->Size
= VariableStoreLength
;
3983 VariableStore
->Format
= VARIABLE_STORE_FORMATTED
;
3984 VariableStore
->State
= VARIABLE_STORE_HEALTHY
;
3985 VariableStore
->Reserved
= 0;
3986 VariableStore
->Reserved1
= 0;
3989 *VariableStoreBase
= (EFI_PHYSICAL_ADDRESS
) (UINTN
) VariableStore
;
3991 HwErrStorageSize
= PcdGet32 (PcdHwErrStorageSize
);
3994 // Note that in EdkII variable driver implementation, Hardware Error Record type variable
3995 // is stored with common variable in the same NV region. So the platform integrator should
3996 // ensure that the value of PcdHwErrStorageSize is less than the value of
3997 // (VariableStoreLength - sizeof (VARIABLE_STORE_HEADER)).
3999 ASSERT (HwErrStorageSize
< (VariableStoreLength
- sizeof (VARIABLE_STORE_HEADER
)));
4001 mVariableModuleGlobal
->CommonVariableSpace
= ((UINTN
) VariableStoreLength
- sizeof (VARIABLE_STORE_HEADER
) - HwErrStorageSize
);
4002 mVariableModuleGlobal
->CommonMaxUserVariableSpace
= mVariableModuleGlobal
->CommonVariableSpace
;
4003 mVariableModuleGlobal
->CommonRuntimeVariableSpace
= mVariableModuleGlobal
->CommonVariableSpace
;
4009 Init non-volatile variable store.
4011 @retval EFI_SUCCESS Function successfully executed.
4012 @retval EFI_OUT_OF_RESOURCES Fail to allocate enough memory resource.
4013 @retval EFI_VOLUME_CORRUPTED Variable Store or Firmware Volume for Variable Store is corrupted.
4017 InitNonVolatileVariableStore (
4021 VARIABLE_HEADER
*Variable
;
4022 VARIABLE_HEADER
*NextVariable
;
4023 EFI_PHYSICAL_ADDRESS VariableStoreBase
;
4027 if (PcdGetBool (PcdEmuVariableNvModeEnable
)) {
4028 Status
= InitEmuNonVolatileVariableStore (&VariableStoreBase
);
4029 if (EFI_ERROR (Status
)) {
4032 mVariableModuleGlobal
->VariableGlobal
.EmuNvMode
= TRUE
;
4033 DEBUG ((DEBUG_INFO
, "Variable driver will work at emulated non-volatile variable mode!\n"));
4035 Status
= InitRealNonVolatileVariableStore (&VariableStoreBase
);
4036 if (EFI_ERROR (Status
)) {
4039 mVariableModuleGlobal
->VariableGlobal
.EmuNvMode
= FALSE
;
4042 mVariableModuleGlobal
->VariableGlobal
.NonVolatileVariableBase
= VariableStoreBase
;
4043 mNvVariableCache
= (VARIABLE_STORE_HEADER
*) (UINTN
) VariableStoreBase
;
4044 mVariableModuleGlobal
->VariableGlobal
.AuthFormat
= (BOOLEAN
)(CompareGuid (&mNvVariableCache
->Signature
, &gEfiAuthenticatedVariableGuid
));
4046 mVariableModuleGlobal
->MaxVariableSize
= PcdGet32 (PcdMaxVariableSize
);
4047 mVariableModuleGlobal
->MaxAuthVariableSize
= ((PcdGet32 (PcdMaxAuthVariableSize
) != 0) ? PcdGet32 (PcdMaxAuthVariableSize
) : mVariableModuleGlobal
->MaxVariableSize
);
4050 // Parse non-volatile variable data and get last variable offset.
4052 Variable
= GetStartPointer (mNvVariableCache
);
4053 while (IsValidVariableHeader (Variable
, GetEndPointer (mNvVariableCache
))) {
4054 NextVariable
= GetNextVariablePtr (Variable
);
4055 VariableSize
= (UINTN
) NextVariable
- (UINTN
) Variable
;
4056 if ((Variable
->Attributes
& (EFI_VARIABLE_NON_VOLATILE
| EFI_VARIABLE_HARDWARE_ERROR_RECORD
)) == (EFI_VARIABLE_NON_VOLATILE
| EFI_VARIABLE_HARDWARE_ERROR_RECORD
)) {
4057 mVariableModuleGlobal
->HwErrVariableTotalSize
+= VariableSize
;
4059 mVariableModuleGlobal
->CommonVariableTotalSize
+= VariableSize
;
4062 Variable
= NextVariable
;
4064 mVariableModuleGlobal
->NonVolatileLastVariableOffset
= (UINTN
) Variable
- (UINTN
) mNvVariableCache
;
4070 Flush the HOB variable to flash.
4072 @param[in] VariableName Name of variable has been updated or deleted.
4073 @param[in] VendorGuid Guid of variable has been updated or deleted.
4077 FlushHobVariableToFlash (
4078 IN CHAR16
*VariableName
,
4079 IN EFI_GUID
*VendorGuid
4083 VARIABLE_STORE_HEADER
*VariableStoreHeader
;
4084 VARIABLE_HEADER
*Variable
;
4086 VARIABLE_POINTER_TRACK VariablePtrTrack
;
4092 // Flush the HOB variable to flash.
4094 if (mVariableModuleGlobal
->VariableGlobal
.HobVariableBase
!= 0) {
4095 VariableStoreHeader
= (VARIABLE_STORE_HEADER
*) (UINTN
) mVariableModuleGlobal
->VariableGlobal
.HobVariableBase
;
4097 // Set HobVariableBase to 0, it can avoid SetVariable to call back.
4099 mVariableModuleGlobal
->VariableGlobal
.HobVariableBase
= 0;
4100 for ( Variable
= GetStartPointer (VariableStoreHeader
)
4101 ; IsValidVariableHeader (Variable
, GetEndPointer (VariableStoreHeader
))
4102 ; Variable
= GetNextVariablePtr (Variable
)
4104 if (Variable
->State
!= VAR_ADDED
) {
4106 // The HOB variable has been set to DELETED state in local.
4110 ASSERT ((Variable
->Attributes
& EFI_VARIABLE_NON_VOLATILE
) != 0);
4111 if (VendorGuid
== NULL
|| VariableName
== NULL
||
4112 !CompareGuid (VendorGuid
, GetVendorGuidPtr (Variable
)) ||
4113 StrCmp (VariableName
, GetVariableNamePtr (Variable
)) != 0) {
4114 VariableData
= GetVariableDataPtr (Variable
);
4115 FindVariable (GetVariableNamePtr (Variable
), GetVendorGuidPtr (Variable
), &VariablePtrTrack
, &mVariableModuleGlobal
->VariableGlobal
, FALSE
);
4116 Status
= UpdateVariable (
4117 GetVariableNamePtr (Variable
),
4118 GetVendorGuidPtr (Variable
),
4120 DataSizeOfVariable (Variable
),
4121 Variable
->Attributes
,
4127 DEBUG ((EFI_D_INFO
, "Variable driver flush the HOB variable to flash: %g %s %r\n", GetVendorGuidPtr (Variable
), GetVariableNamePtr (Variable
), Status
));
4130 // The updated or deleted variable is matched with this HOB variable.
4131 // Don't break here because we will try to set other HOB variables
4132 // since this variable could be set successfully.
4134 Status
= EFI_SUCCESS
;
4136 if (!EFI_ERROR (Status
)) {
4138 // If set variable successful, or the updated or deleted variable is matched with the HOB variable,
4139 // set the HOB variable to DELETED state in local.
4141 DEBUG ((EFI_D_INFO
, "Variable driver set the HOB variable to DELETED state in local: %g %s\n", GetVendorGuidPtr (Variable
), GetVariableNamePtr (Variable
)));
4142 Variable
->State
&= VAR_DELETED
;
4149 // We still have HOB variable(s) not flushed in flash.
4151 mVariableModuleGlobal
->VariableGlobal
.HobVariableBase
= (EFI_PHYSICAL_ADDRESS
) (UINTN
) VariableStoreHeader
;
4154 // All HOB variables have been flushed in flash.
4156 DEBUG ((EFI_D_INFO
, "Variable driver: all HOB variables have been flushed in flash.\n"));
4157 if (!AtRuntime ()) {
4158 FreePool ((VOID
*) VariableStoreHeader
);
4166 Initializes variable write service.
4168 @retval EFI_SUCCESS Function successfully executed.
4169 @retval Others Fail to initialize the variable service.
4173 VariableWriteServiceInitialize (
4180 VARIABLE_ENTRY_PROPERTY
*VariableEntry
;
4182 AcquireLockOnlyAtBootTime(&mVariableModuleGlobal
->VariableGlobal
.VariableServicesLock
);
4185 // Check if the free area is really free.
4187 for (Index
= mVariableModuleGlobal
->NonVolatileLastVariableOffset
; Index
< mNvVariableCache
->Size
; Index
++) {
4188 Data
= ((UINT8
*) mNvVariableCache
)[Index
];
4191 // There must be something wrong in variable store, do reclaim operation.
4194 mVariableModuleGlobal
->VariableGlobal
.NonVolatileVariableBase
,
4195 &mVariableModuleGlobal
->NonVolatileLastVariableOffset
,
4201 if (EFI_ERROR (Status
)) {
4202 ReleaseLockOnlyAtBootTime (&mVariableModuleGlobal
->VariableGlobal
.VariableServicesLock
);
4209 FlushHobVariableToFlash (NULL
, NULL
);
4211 Status
= EFI_SUCCESS
;
4212 ZeroMem (&mAuthContextOut
, sizeof (mAuthContextOut
));
4213 if (mVariableModuleGlobal
->VariableGlobal
.AuthFormat
) {
4215 // Authenticated variable initialize.
4217 mAuthContextIn
.StructSize
= sizeof (AUTH_VAR_LIB_CONTEXT_IN
);
4218 mAuthContextIn
.MaxAuthVariableSize
= mVariableModuleGlobal
->MaxAuthVariableSize
- GetVariableHeaderSize ();
4219 Status
= AuthVariableLibInitialize (&mAuthContextIn
, &mAuthContextOut
);
4220 if (!EFI_ERROR (Status
)) {
4221 DEBUG ((EFI_D_INFO
, "Variable driver will work with auth variable support!\n"));
4222 mVariableModuleGlobal
->VariableGlobal
.AuthSupport
= TRUE
;
4223 if (mAuthContextOut
.AuthVarEntry
!= NULL
) {
4224 for (Index
= 0; Index
< mAuthContextOut
.AuthVarEntryCount
; Index
++) {
4225 VariableEntry
= &mAuthContextOut
.AuthVarEntry
[Index
];
4226 Status
= VarCheckLibVariablePropertySet (
4227 VariableEntry
->Name
,
4228 VariableEntry
->Guid
,
4229 &VariableEntry
->VariableProperty
4231 ASSERT_EFI_ERROR (Status
);
4234 } else if (Status
== EFI_UNSUPPORTED
) {
4235 DEBUG ((EFI_D_INFO
, "NOTICE - AuthVariableLibInitialize() returns %r!\n", Status
));
4236 DEBUG ((EFI_D_INFO
, "Variable driver will continue to work without auth variable support!\n"));
4237 mVariableModuleGlobal
->VariableGlobal
.AuthSupport
= FALSE
;
4238 Status
= EFI_SUCCESS
;
4242 if (!EFI_ERROR (Status
)) {
4243 for (Index
= 0; Index
< ARRAY_SIZE (mVariableEntryProperty
); Index
++) {
4244 VariableEntry
= &mVariableEntryProperty
[Index
];
4245 Status
= VarCheckLibVariablePropertySet (VariableEntry
->Name
, VariableEntry
->Guid
, &VariableEntry
->VariableProperty
);
4246 ASSERT_EFI_ERROR (Status
);
4250 ReleaseLockOnlyAtBootTime (&mVariableModuleGlobal
->VariableGlobal
.VariableServicesLock
);
4253 // Initialize MOR Lock variable.
4261 Convert normal variable storage to the allocated auth variable storage.
4263 @param[in] NormalVarStorage Pointer to the normal variable storage header
4265 @retval the allocated auth variable storage
4268 ConvertNormalVarStorageToAuthVarStorage (
4269 VARIABLE_STORE_HEADER
*NormalVarStorage
4272 VARIABLE_HEADER
*StartPtr
;
4274 VARIABLE_HEADER
*EndPtr
;
4275 UINTN AuthVarStroageSize
;
4276 AUTHENTICATED_VARIABLE_HEADER
*AuthStartPtr
;
4277 VARIABLE_STORE_HEADER
*AuthVarStorage
;
4279 AuthVarStroageSize
= sizeof (VARIABLE_STORE_HEADER
);
4281 // Set AuthFormat as FALSE for normal variable storage
4283 mVariableModuleGlobal
->VariableGlobal
.AuthFormat
= FALSE
;
4286 // Calculate Auth Variable Storage Size
4288 StartPtr
= GetStartPointer (NormalVarStorage
);
4289 EndPtr
= GetEndPointer (NormalVarStorage
);
4290 while (StartPtr
< EndPtr
) {
4291 if (StartPtr
->State
== VAR_ADDED
) {
4292 AuthVarStroageSize
= HEADER_ALIGN (AuthVarStroageSize
);
4293 AuthVarStroageSize
+= sizeof (AUTHENTICATED_VARIABLE_HEADER
);
4294 AuthVarStroageSize
+= StartPtr
->NameSize
+ GET_PAD_SIZE (StartPtr
->NameSize
);
4295 AuthVarStroageSize
+= StartPtr
->DataSize
+ GET_PAD_SIZE (StartPtr
->DataSize
);
4297 StartPtr
= GetNextVariablePtr (StartPtr
);
4301 // Allocate Runtime memory for Auth Variable Storage
4303 AuthVarStorage
= AllocateRuntimeZeroPool (AuthVarStroageSize
);
4304 ASSERT (AuthVarStorage
!= NULL
);
4305 if (AuthVarStorage
== NULL
) {
4310 // Copy Variable from Normal storage to Auth storage
4312 StartPtr
= GetStartPointer (NormalVarStorage
);
4313 EndPtr
= GetEndPointer (NormalVarStorage
);
4314 AuthStartPtr
= (AUTHENTICATED_VARIABLE_HEADER
*) GetStartPointer (AuthVarStorage
);
4315 while (StartPtr
< EndPtr
) {
4316 if (StartPtr
->State
== VAR_ADDED
) {
4317 AuthStartPtr
= (AUTHENTICATED_VARIABLE_HEADER
*) HEADER_ALIGN (AuthStartPtr
);
4319 // Copy Variable Header
4321 AuthStartPtr
->StartId
= StartPtr
->StartId
;
4322 AuthStartPtr
->State
= StartPtr
->State
;
4323 AuthStartPtr
->Attributes
= StartPtr
->Attributes
;
4324 AuthStartPtr
->NameSize
= StartPtr
->NameSize
;
4325 AuthStartPtr
->DataSize
= StartPtr
->DataSize
;
4326 CopyGuid (&AuthStartPtr
->VendorGuid
, &StartPtr
->VendorGuid
);
4328 // Copy Variable Name
4330 NextPtr
= (UINT8
*) (AuthStartPtr
+ 1);
4331 CopyMem (NextPtr
, GetVariableNamePtr (StartPtr
), AuthStartPtr
->NameSize
);
4333 // Copy Variable Data
4335 NextPtr
= NextPtr
+ AuthStartPtr
->NameSize
+ GET_PAD_SIZE (AuthStartPtr
->NameSize
);
4336 CopyMem (NextPtr
, GetVariableDataPtr (StartPtr
), AuthStartPtr
->DataSize
);
4338 // Go to next variable
4340 AuthStartPtr
= (AUTHENTICATED_VARIABLE_HEADER
*) (NextPtr
+ AuthStartPtr
->DataSize
+ GET_PAD_SIZE (AuthStartPtr
->DataSize
));
4342 StartPtr
= GetNextVariablePtr (StartPtr
);
4345 // Update Auth Storage Header
4347 AuthVarStorage
->Format
= NormalVarStorage
->Format
;
4348 AuthVarStorage
->State
= NormalVarStorage
->State
;
4349 AuthVarStorage
->Size
= (UINT32
)((UINTN
)AuthStartPtr
- (UINTN
)AuthVarStorage
);
4350 CopyGuid (&AuthVarStorage
->Signature
, &gEfiAuthenticatedVariableGuid
);
4351 ASSERT (AuthVarStorage
->Size
<= AuthVarStroageSize
);
4354 // Restore AuthFormat
4356 mVariableModuleGlobal
->VariableGlobal
.AuthFormat
= TRUE
;
4357 return AuthVarStorage
;
4361 Get HOB variable store.
4363 @param[in] VariableGuid NV variable store signature.
4365 @retval EFI_SUCCESS Function successfully executed.
4366 @retval EFI_OUT_OF_RESOURCES Fail to allocate enough memory resource.
4370 GetHobVariableStore (
4371 IN EFI_GUID
*VariableGuid
4374 VARIABLE_STORE_HEADER
*VariableStoreHeader
;
4375 UINT64 VariableStoreLength
;
4376 EFI_HOB_GUID_TYPE
*GuidHob
;
4377 BOOLEAN NeedConvertNormalToAuth
;
4380 // Make sure there is no more than one Variable HOB.
4383 GuidHob
= GetFirstGuidHob (&gEfiAuthenticatedVariableGuid
);
4384 if (GuidHob
!= NULL
) {
4385 if ((GetNextGuidHob (&gEfiAuthenticatedVariableGuid
, GET_NEXT_HOB (GuidHob
)) != NULL
)) {
4386 DEBUG ((DEBUG_ERROR
, "ERROR: Found two Auth Variable HOBs\n"));
4388 } else if (GetFirstGuidHob (&gEfiVariableGuid
) != NULL
) {
4389 DEBUG ((DEBUG_ERROR
, "ERROR: Found one Auth + one Normal Variable HOBs\n"));
4393 GuidHob
= GetFirstGuidHob (&gEfiVariableGuid
);
4394 if (GuidHob
!= NULL
) {
4395 if ((GetNextGuidHob (&gEfiVariableGuid
, GET_NEXT_HOB (GuidHob
)) != NULL
)) {
4396 DEBUG ((DEBUG_ERROR
, "ERROR: Found two Normal Variable HOBs\n"));
4404 // Combinations supported:
4405 // 1. Normal NV variable store +
4406 // Normal HOB variable store
4407 // 2. Auth NV variable store +
4408 // Auth HOB variable store
4409 // 3. Auth NV variable store +
4410 // Normal HOB variable store (code will convert it to Auth Format)
4412 NeedConvertNormalToAuth
= FALSE
;
4413 GuidHob
= GetFirstGuidHob (VariableGuid
);
4414 if (GuidHob
== NULL
&& VariableGuid
== &gEfiAuthenticatedVariableGuid
) {
4416 // Try getting it from normal variable HOB
4418 GuidHob
= GetFirstGuidHob (&gEfiVariableGuid
);
4419 NeedConvertNormalToAuth
= TRUE
;
4421 if (GuidHob
!= NULL
) {
4422 VariableStoreHeader
= GET_GUID_HOB_DATA (GuidHob
);
4423 VariableStoreLength
= GuidHob
->Header
.HobLength
- sizeof (EFI_HOB_GUID_TYPE
);
4424 if (GetVariableStoreStatus (VariableStoreHeader
) == EfiValid
) {
4425 if (!NeedConvertNormalToAuth
) {
4426 mVariableModuleGlobal
->VariableGlobal
.HobVariableBase
= (EFI_PHYSICAL_ADDRESS
) (UINTN
) AllocateRuntimeCopyPool ((UINTN
) VariableStoreLength
, (VOID
*) VariableStoreHeader
);
4428 mVariableModuleGlobal
->VariableGlobal
.HobVariableBase
= (EFI_PHYSICAL_ADDRESS
) (UINTN
) ConvertNormalVarStorageToAuthVarStorage ((VOID
*) VariableStoreHeader
);
4430 if (mVariableModuleGlobal
->VariableGlobal
.HobVariableBase
== 0) {
4431 return EFI_OUT_OF_RESOURCES
;
4434 DEBUG ((EFI_D_ERROR
, "HOB Variable Store header is corrupted!\n"));
4442 Initializes variable store area for non-volatile and volatile variable.
4444 @retval EFI_SUCCESS Function successfully executed.
4445 @retval EFI_OUT_OF_RESOURCES Fail to allocate enough memory resource.
4449 VariableCommonInitialize (
4454 VARIABLE_STORE_HEADER
*VolatileVariableStore
;
4456 EFI_GUID
*VariableGuid
;
4459 // Allocate runtime memory for variable driver global structure.
4461 mVariableModuleGlobal
= AllocateRuntimeZeroPool (sizeof (VARIABLE_MODULE_GLOBAL
));
4462 if (mVariableModuleGlobal
== NULL
) {
4463 return EFI_OUT_OF_RESOURCES
;
4466 InitializeLock (&mVariableModuleGlobal
->VariableGlobal
.VariableServicesLock
, TPL_NOTIFY
);
4469 // Init non-volatile variable store.
4471 Status
= InitNonVolatileVariableStore ();
4472 if (EFI_ERROR (Status
)) {
4473 FreePool (mVariableModuleGlobal
);
4478 // mVariableModuleGlobal->VariableGlobal.AuthFormat
4479 // has been initialized in InitNonVolatileVariableStore().
4481 if (mVariableModuleGlobal
->VariableGlobal
.AuthFormat
) {
4482 DEBUG ((EFI_D_INFO
, "Variable driver will work with auth variable format!\n"));
4484 // Set AuthSupport to FALSE first, VariableWriteServiceInitialize() will initialize it.
4486 mVariableModuleGlobal
->VariableGlobal
.AuthSupport
= FALSE
;
4487 VariableGuid
= &gEfiAuthenticatedVariableGuid
;
4489 DEBUG ((EFI_D_INFO
, "Variable driver will work without auth variable support!\n"));
4490 mVariableModuleGlobal
->VariableGlobal
.AuthSupport
= FALSE
;
4491 VariableGuid
= &gEfiVariableGuid
;
4495 // Get HOB variable store.
4497 Status
= GetHobVariableStore (VariableGuid
);
4498 if (EFI_ERROR (Status
)) {
4499 if (mNvFvHeaderCache
!= NULL
) {
4500 FreePool (mNvFvHeaderCache
);
4502 FreePool (mVariableModuleGlobal
);
4506 mVariableModuleGlobal
->MaxVolatileVariableSize
= ((PcdGet32 (PcdMaxVolatileVariableSize
) != 0) ?
4507 PcdGet32 (PcdMaxVolatileVariableSize
) :
4508 mVariableModuleGlobal
->MaxVariableSize
4511 // Allocate memory for volatile variable store, note that there is a scratch space to store scratch data.
4513 ScratchSize
= GetMaxVariableSize ();
4514 mVariableModuleGlobal
->ScratchBufferSize
= ScratchSize
;
4515 VolatileVariableStore
= AllocateRuntimePool (PcdGet32 (PcdVariableStoreSize
) + ScratchSize
);
4516 if (VolatileVariableStore
== NULL
) {
4517 if (mVariableModuleGlobal
->VariableGlobal
.HobVariableBase
!= 0) {
4518 FreePool ((VOID
*) (UINTN
) mVariableModuleGlobal
->VariableGlobal
.HobVariableBase
);
4520 if (mNvFvHeaderCache
!= NULL
) {
4521 FreePool (mNvFvHeaderCache
);
4523 FreePool (mVariableModuleGlobal
);
4524 return EFI_OUT_OF_RESOURCES
;
4527 SetMem (VolatileVariableStore
, PcdGet32 (PcdVariableStoreSize
) + ScratchSize
, 0xff);
4530 // Initialize Variable Specific Data.
4532 mVariableModuleGlobal
->VariableGlobal
.VolatileVariableBase
= (EFI_PHYSICAL_ADDRESS
) (UINTN
) VolatileVariableStore
;
4533 mVariableModuleGlobal
->VolatileLastVariableOffset
= (UINTN
) GetStartPointer (VolatileVariableStore
) - (UINTN
) VolatileVariableStore
;
4535 CopyGuid (&VolatileVariableStore
->Signature
, VariableGuid
);
4536 VolatileVariableStore
->Size
= PcdGet32 (PcdVariableStoreSize
);
4537 VolatileVariableStore
->Format
= VARIABLE_STORE_FORMATTED
;
4538 VolatileVariableStore
->State
= VARIABLE_STORE_HEALTHY
;
4539 VolatileVariableStore
->Reserved
= 0;
4540 VolatileVariableStore
->Reserved1
= 0;
4547 Get the proper fvb handle and/or fvb protocol by the given Flash address.
4549 @param[in] Address The Flash address.
4550 @param[out] FvbHandle In output, if it is not NULL, it points to the proper FVB handle.
4551 @param[out] FvbProtocol In output, if it is not NULL, it points to the proper FVB protocol.
4555 GetFvbInfoByAddress (
4556 IN EFI_PHYSICAL_ADDRESS Address
,
4557 OUT EFI_HANDLE
*FvbHandle OPTIONAL
,
4558 OUT EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
**FvbProtocol OPTIONAL
4562 EFI_HANDLE
*HandleBuffer
;
4565 EFI_PHYSICAL_ADDRESS FvbBaseAddress
;
4566 EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*Fvb
;
4567 EFI_FVB_ATTRIBUTES_2 Attributes
;
4569 UINTN NumberOfBlocks
;
4571 HandleBuffer
= NULL
;
4573 // Get all FVB handles.
4575 Status
= GetFvbCountAndBuffer (&HandleCount
, &HandleBuffer
);
4576 if (EFI_ERROR (Status
)) {
4577 return EFI_NOT_FOUND
;
4581 // Get the FVB to access variable store.
4584 for (Index
= 0; Index
< HandleCount
; Index
+= 1, Status
= EFI_NOT_FOUND
, Fvb
= NULL
) {
4585 Status
= GetFvbByHandle (HandleBuffer
[Index
], &Fvb
);
4586 if (EFI_ERROR (Status
)) {
4587 Status
= EFI_NOT_FOUND
;
4592 // Ensure this FVB protocol supported Write operation.
4594 Status
= Fvb
->GetAttributes (Fvb
, &Attributes
);
4595 if (EFI_ERROR (Status
) || ((Attributes
& EFI_FVB2_WRITE_STATUS
) == 0)) {
4600 // Compare the address and select the right one.
4602 Status
= Fvb
->GetPhysicalAddress (Fvb
, &FvbBaseAddress
);
4603 if (EFI_ERROR (Status
)) {
4608 // Assume one FVB has one type of BlockSize.
4610 Status
= Fvb
->GetBlockSize (Fvb
, 0, &BlockSize
, &NumberOfBlocks
);
4611 if (EFI_ERROR (Status
)) {
4615 if ((Address
>= FvbBaseAddress
) && (Address
< (FvbBaseAddress
+ BlockSize
* NumberOfBlocks
))) {
4616 if (FvbHandle
!= NULL
) {
4617 *FvbHandle
= HandleBuffer
[Index
];
4619 if (FvbProtocol
!= NULL
) {
4622 Status
= EFI_SUCCESS
;
4626 FreePool (HandleBuffer
);
4629 Status
= EFI_NOT_FOUND
;