3 Implement all four UEFI Runtime Variable services for the nonvolatile
4 and volatile storage space and install variable architecture protocol.
6 Copyright (c) 2006 - 2009, Intel Corporation
7 All rights reserved. This program and the accompanying materials
8 are licensed and made available under the terms and conditions of the BSD License
9 which accompanies this distribution. The full text of the license may be found at
10 http://opensource.org/licenses/bsd-license.php
12 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
13 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
19 VARIABLE_MODULE_GLOBAL
*mVariableModuleGlobal
;
20 EFI_EVENT mVirtualAddressChangeEvent
= NULL
;
21 EFI_HANDLE mHandle
= NULL
;
24 /// The current Hii implementation accesses this variable many times on every boot.
25 /// Other common variables are only accessed once. This is why this cache algorithm
26 /// only targets a single variable. Probably to get an performance improvement out of
27 /// a Cache you would need a cache that improves the search performance for a variable.
29 VARIABLE_CACHE_ENTRY mVariableCache
[] = {
31 &gEfiGlobalVariableGuid
,
39 VARIABLE_INFO_ENTRY
*gVariableInfo
= NULL
;
40 EFI_EVENT mFvbRegistration
= NULL
;
44 Acquires lock only at boot time. Simply returns at runtime.
46 This is a temperary function which will be removed when
47 EfiAcquireLock() in UefiLib can handle the call in UEFI
48 Runtimer driver in RT phase.
49 It calls EfiAcquireLock() at boot time, and simply returns
52 @param Lock A pointer to the lock to acquire
56 AcquireLockOnlyAtBootTime (
60 if (!EfiAtRuntime ()) {
61 EfiAcquireLock (Lock
);
66 Releases lock only at boot time. Simply returns at runtime.
68 This is a temperary function which will be removed when
69 EfiReleaseLock() in UefiLib can handle the call in UEFI
70 Runtimer driver in RT phase.
71 It calls EfiReleaseLock() at boot time, and simply returns
74 @param Lock A pointer to the lock to release
78 ReleaseLockOnlyAtBootTime (
82 if (!EfiAtRuntime ()) {
83 EfiReleaseLock (Lock
);
89 Routine used to track statistical information about variable usage.
90 The data is stored in the EFI system table so it can be accessed later.
91 VariableInfo.efi can dump out the table. Only Boot Services variable
92 accesses are tracked by this code. The PcdVariableCollectStatistics
93 build flag controls if this feature is enabled.
95 A read that hits in the cache will have Read and Cache true for
96 the transaction. Data is allocated by this routine, but never
99 @param[in] VariableName Name of the Variable to track
100 @param[in] VendorGuid Guid of the Variable to track
101 @param[in] Volatile TRUE if volatile FALSE if non-volatile
102 @param[in] Read TRUE if GetVariable() was called
103 @param[in] Write TRUE if SetVariable() was called
104 @param[in] Delete TRUE if deleted via SetVariable()
105 @param[in] Cache TRUE for a cache hit.
110 IN CHAR16
*VariableName
,
111 IN EFI_GUID
*VendorGuid
,
119 VARIABLE_INFO_ENTRY
*Entry
;
121 if (FeaturePcdGet (PcdVariableCollectStatistics
)) {
123 if (EfiAtRuntime ()) {
124 // Don't collect statistics at runtime
128 if (gVariableInfo
== NULL
) {
130 // on the first call allocate a entry and place a pointer to it in
131 // the EFI System Table
133 gVariableInfo
= AllocateZeroPool (sizeof (VARIABLE_INFO_ENTRY
));
134 ASSERT (gVariableInfo
!= NULL
);
136 CopyGuid (&gVariableInfo
->VendorGuid
, VendorGuid
);
137 gVariableInfo
->Name
= AllocatePool (StrLen (VariableName
));
138 ASSERT (gVariableInfo
->Name
!= NULL
);
139 StrCpy (gVariableInfo
->Name
, VariableName
);
140 gVariableInfo
->Volatile
= Volatile
;
142 gBS
->InstallConfigurationTable (&gEfiVariableGuid
, gVariableInfo
);
146 for (Entry
= gVariableInfo
; Entry
!= NULL
; Entry
= Entry
->Next
) {
147 if (CompareGuid (VendorGuid
, &Entry
->VendorGuid
)) {
148 if (StrCmp (VariableName
, Entry
->Name
) == 0) {
156 Entry
->DeleteCount
++;
166 if (Entry
->Next
== NULL
) {
168 // If the entry is not in the table add it.
169 // Next iteration of the loop will fill in the data
171 Entry
->Next
= AllocateZeroPool (sizeof (VARIABLE_INFO_ENTRY
));
172 ASSERT (Entry
->Next
!= NULL
);
174 CopyGuid (&Entry
->Next
->VendorGuid
, VendorGuid
);
175 Entry
->Next
->Name
= AllocatePool (StrLen (VariableName
));
176 ASSERT (Entry
->Next
->Name
!= NULL
);
177 StrCpy (Entry
->Next
->Name
, VariableName
);
178 Entry
->Next
->Volatile
= Volatile
;
188 This code checks if variable header is valid or not.
190 @param Variable Pointer to the Variable Header.
192 @retval TRUE Variable header is valid.
193 @retval FALSE Variable header is not valid.
197 IsValidVariableHeader (
198 IN VARIABLE_HEADER
*Variable
201 if (Variable
== NULL
|| Variable
->StartId
!= VARIABLE_DATA
) {
211 This function writes data to the FWH at the correct LBA even if the LBAs
214 @param Global Pointer to VARAIBLE_GLOBAL structure
215 @param Volatile Point out the Variable is Volatile or Non-Volatile
216 @param SetByIndex TRUE if target pointer is given as index
217 FALSE if target pointer is absolute
218 @param Fvb Pointer to the writable FVB protocol
219 @param DataPtrIndex Pointer to the Data from the end of VARIABLE_STORE_HEADER
221 @param DataSize Size of data to be written
222 @param Buffer Pointer to the buffer from which data is written
224 @retval EFI_INVALID_PARAMETER Parameters not valid
225 @retval EFI_SUCCESS Variable store successfully updated
229 UpdateVariableStore (
230 IN VARIABLE_GLOBAL
*Global
,
232 IN BOOLEAN SetByIndex
,
233 IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*Fvb
,
234 IN UINTN DataPtrIndex
,
239 EFI_FV_BLOCK_MAP_ENTRY
*PtrBlockMapEntry
;
247 EFI_FIRMWARE_VOLUME_HEADER
*FwVolHeader
;
248 VARIABLE_STORE_HEADER
*VolatileBase
;
249 EFI_PHYSICAL_ADDRESS FvVolHdr
;
250 EFI_PHYSICAL_ADDRESS DataPtr
;
254 DataPtr
= DataPtrIndex
;
257 // Check if the Data is Volatile
260 Status
= Fvb
->GetPhysicalAddress(Fvb
, &FvVolHdr
);
261 ASSERT_EFI_ERROR (Status
);
263 FwVolHeader
= (EFI_FIRMWARE_VOLUME_HEADER
*) ((UINTN
) FvVolHdr
);
265 // Data Pointer should point to the actual Address where data is to be
269 DataPtr
+= mVariableModuleGlobal
->VariableGlobal
.NonVolatileVariableBase
;
272 if ((DataPtr
+ DataSize
) >= ((EFI_PHYSICAL_ADDRESS
) (UINTN
) ((UINT8
*) FwVolHeader
+ FwVolHeader
->FvLength
))) {
273 return EFI_INVALID_PARAMETER
;
277 // Data Pointer should point to the actual Address where data is to be
280 VolatileBase
= (VARIABLE_STORE_HEADER
*) ((UINTN
) mVariableModuleGlobal
->VariableGlobal
.VolatileVariableBase
);
282 DataPtr
+= mVariableModuleGlobal
->VariableGlobal
.VolatileVariableBase
;
285 if ((DataPtr
+ DataSize
) >= ((UINTN
) ((UINT8
*) VolatileBase
+ VolatileBase
->Size
))) {
286 return EFI_INVALID_PARAMETER
;
290 // If Volatile Variable just do a simple mem copy.
292 CopyMem ((UINT8
*)(UINTN
)DataPtr
, Buffer
, DataSize
);
297 // If we are here we are dealing with Non-Volatile Variables
299 LinearOffset
= (UINTN
) FwVolHeader
;
300 CurrWritePtr
= (UINTN
) DataPtr
;
301 CurrWriteSize
= DataSize
;
305 if (CurrWritePtr
< LinearOffset
) {
306 return EFI_INVALID_PARAMETER
;
309 for (PtrBlockMapEntry
= FwVolHeader
->BlockMap
; PtrBlockMapEntry
->NumBlocks
!= 0; PtrBlockMapEntry
++) {
310 for (BlockIndex2
= 0; BlockIndex2
< PtrBlockMapEntry
->NumBlocks
; BlockIndex2
++) {
312 // Check to see if the Variable Writes are spanning through multiple
315 if ((CurrWritePtr
>= LinearOffset
) && (CurrWritePtr
< LinearOffset
+ PtrBlockMapEntry
->Length
)) {
316 if ((CurrWritePtr
+ CurrWriteSize
) <= (LinearOffset
+ PtrBlockMapEntry
->Length
)) {
317 Status
= Fvb
->Write (
320 (UINTN
) (CurrWritePtr
- LinearOffset
),
326 Size
= (UINT32
) (LinearOffset
+ PtrBlockMapEntry
->Length
- CurrWritePtr
);
327 Status
= Fvb
->Write (
330 (UINTN
) (CurrWritePtr
- LinearOffset
),
334 if (EFI_ERROR (Status
)) {
338 CurrWritePtr
= LinearOffset
+ PtrBlockMapEntry
->Length
;
339 CurrBuffer
= CurrBuffer
+ Size
;
340 CurrWriteSize
= CurrWriteSize
- Size
;
344 LinearOffset
+= PtrBlockMapEntry
->Length
;
355 This code gets the current status of Variable Store.
357 @param VarStoreHeader Pointer to the Variable Store Header.
359 @retval EfiRaw Variable store status is raw
360 @retval EfiValid Variable store status is valid
361 @retval EfiInvalid Variable store status is invalid
364 VARIABLE_STORE_STATUS
365 GetVariableStoreStatus (
366 IN VARIABLE_STORE_HEADER
*VarStoreHeader
369 if (CompareGuid (&VarStoreHeader
->Signature
, &gEfiVariableGuid
) &&
370 VarStoreHeader
->Format
== VARIABLE_STORE_FORMATTED
&&
371 VarStoreHeader
->State
== VARIABLE_STORE_HEALTHY
375 } else if (((UINT32
*)(&VarStoreHeader
->Signature
))[0] == 0xffffffff &&
376 ((UINT32
*)(&VarStoreHeader
->Signature
))[1] == 0xffffffff &&
377 ((UINT32
*)(&VarStoreHeader
->Signature
))[2] == 0xffffffff &&
378 ((UINT32
*)(&VarStoreHeader
->Signature
))[3] == 0xffffffff &&
379 VarStoreHeader
->Size
== 0xffffffff &&
380 VarStoreHeader
->Format
== 0xff &&
381 VarStoreHeader
->State
== 0xff
393 This code gets the size of name of variable.
395 @param Variable Pointer to the Variable Header
397 @return UINTN Size of variable in bytes
402 IN VARIABLE_HEADER
*Variable
405 if (Variable
->State
== (UINT8
) (-1) ||
406 Variable
->DataSize
== (UINT32
) (-1) ||
407 Variable
->NameSize
== (UINT32
) (-1) ||
408 Variable
->Attributes
== (UINT32
) (-1)) {
411 return (UINTN
) Variable
->NameSize
;
416 This code gets the size of variable data.
418 @param Variable Pointer to the Variable Header
420 @return Size of variable in bytes
425 IN VARIABLE_HEADER
*Variable
428 if (Variable
->State
== (UINT8
) (-1) ||
429 Variable
->DataSize
== (UINT32
) (-1) ||
430 Variable
->NameSize
== (UINT32
) (-1) ||
431 Variable
->Attributes
== (UINT32
) (-1)) {
434 return (UINTN
) Variable
->DataSize
;
439 This code gets the pointer to the variable name.
441 @param Variable Pointer to the Variable Header
443 @return Pointer to Variable Name which is Unicode encoding
448 IN VARIABLE_HEADER
*Variable
452 return (CHAR16
*) (Variable
+ 1);
457 This code gets the pointer to the variable data.
459 @param Variable Pointer to the Variable Header
461 @return Pointer to Variable Data
466 IN VARIABLE_HEADER
*Variable
472 // Be careful about pad size for alignment
474 Value
= (UINTN
) GetVariableNamePtr (Variable
);
475 Value
+= NameSizeOfVariable (Variable
);
476 Value
+= GET_PAD_SIZE (NameSizeOfVariable (Variable
));
478 return (UINT8
*) Value
;
484 This code gets the pointer to the next variable header.
486 @param Variable Pointer to the Variable Header
488 @return Pointer to next variable header
493 IN VARIABLE_HEADER
*Variable
498 if (!IsValidVariableHeader (Variable
)) {
502 Value
= (UINTN
) GetVariableDataPtr (Variable
);
503 Value
+= DataSizeOfVariable (Variable
);
504 Value
+= GET_PAD_SIZE (DataSizeOfVariable (Variable
));
507 // Be careful about pad size for alignment
509 return (VARIABLE_HEADER
*) HEADER_ALIGN (Value
);
514 Gets the pointer to the first variable header in given variable store area.
516 @param VarStoreHeader Pointer to the Variable Store Header.
518 @return Pointer to the first variable header
523 IN VARIABLE_STORE_HEADER
*VarStoreHeader
527 // The end of variable store
529 return (VARIABLE_HEADER
*) HEADER_ALIGN (VarStoreHeader
+ 1);
534 Gets the pointer to the end of the variable storage area.
536 This function gets pointer to the end of the variable storage
537 area, according to the input variable store header.
539 @param VarStoreHeader Pointer to the Variable Store Header
541 @return Pointer to the end of the variable storage area
546 IN VARIABLE_STORE_HEADER
*VarStoreHeader
550 // The end of variable store
552 return (VARIABLE_HEADER
*) HEADER_ALIGN ((UINTN
) VarStoreHeader
+ VarStoreHeader
->Size
);
558 Variable store garbage collection and reclaim operation.
560 @param VariableBase Base address of variable store
561 @param LastVariableOffset Offset of last variable
562 @param IsVolatile The variable store is volatile or not,
563 if it is non-volatile, need FTW
564 @param UpdatingVariable Pointer to updateing variable.
566 @return EFI_OUT_OF_RESOURCES
573 IN EFI_PHYSICAL_ADDRESS VariableBase
,
574 OUT UINTN
*LastVariableOffset
,
575 IN BOOLEAN IsVolatile
,
576 IN VARIABLE_HEADER
*UpdatingVariable
579 VARIABLE_HEADER
*Variable
;
580 VARIABLE_HEADER
*AddedVariable
;
581 VARIABLE_HEADER
*NextVariable
;
582 VARIABLE_HEADER
*NextAddedVariable
;
583 VARIABLE_STORE_HEADER
*VariableStoreHeader
;
585 UINTN MaximumBufferSize
;
587 UINTN VariableNameSize
;
588 UINTN UpdatingVariableNameSize
;
595 CHAR16
*VariableNamePtr
;
596 CHAR16
*UpdatingVariableNamePtr
;
598 VariableStoreHeader
= (VARIABLE_STORE_HEADER
*) ((UINTN
) VariableBase
);
601 // Start Pointers for the variable.
603 Variable
= GetStartPointer (VariableStoreHeader
);
604 MaximumBufferSize
= sizeof (VARIABLE_STORE_HEADER
);
606 while (IsValidVariableHeader (Variable
)) {
607 NextVariable
= GetNextVariablePtr (Variable
);
608 if (Variable
->State
== VAR_ADDED
||
609 Variable
->State
== (VAR_IN_DELETED_TRANSITION
& VAR_ADDED
)
611 VariableSize
= (UINTN
) NextVariable
- (UINTN
) Variable
;
612 MaximumBufferSize
+= VariableSize
;
615 Variable
= NextVariable
;
619 // Reserve the 1 Bytes with Oxff to identify the
620 // end of the variable buffer.
622 MaximumBufferSize
+= 1;
623 ValidBuffer
= AllocatePool (MaximumBufferSize
);
624 if (ValidBuffer
== NULL
) {
625 return EFI_OUT_OF_RESOURCES
;
628 SetMem (ValidBuffer
, MaximumBufferSize
, 0xff);
631 // Copy variable store header
633 CopyMem (ValidBuffer
, VariableStoreHeader
, sizeof (VARIABLE_STORE_HEADER
));
634 CurrPtr
= (UINT8
*) GetStartPointer ((VARIABLE_STORE_HEADER
*) ValidBuffer
);
637 // Reinstall all ADDED variables as long as they are not identical to Updating Variable
639 Variable
= GetStartPointer (VariableStoreHeader
);
640 while (IsValidVariableHeader (Variable
)) {
641 NextVariable
= GetNextVariablePtr (Variable
);
642 if (Variable
->State
== VAR_ADDED
) {
643 if (UpdatingVariable
!= NULL
) {
644 if (UpdatingVariable
== Variable
) {
645 Variable
= NextVariable
;
649 VariableNameSize
= NameSizeOfVariable(Variable
);
650 UpdatingVariableNameSize
= NameSizeOfVariable(UpdatingVariable
);
652 VariableNamePtr
= GetVariableNamePtr (Variable
);
653 UpdatingVariableNamePtr
= GetVariableNamePtr (UpdatingVariable
);
654 if (CompareGuid (&Variable
->VendorGuid
, &UpdatingVariable
->VendorGuid
) &&
655 VariableNameSize
== UpdatingVariableNameSize
&&
656 CompareMem (VariableNamePtr
, UpdatingVariableNamePtr
, VariableNameSize
) == 0 ) {
657 Variable
= NextVariable
;
661 VariableSize
= (UINTN
) NextVariable
- (UINTN
) Variable
;
662 CopyMem (CurrPtr
, (UINT8
*) Variable
, VariableSize
);
663 CurrPtr
+= VariableSize
;
665 Variable
= NextVariable
;
669 // Reinstall the variable being updated if it is not NULL
671 if (UpdatingVariable
!= NULL
) {
672 VariableSize
= (UINTN
)(GetNextVariablePtr (UpdatingVariable
)) - (UINTN
)UpdatingVariable
;
673 CopyMem (CurrPtr
, (UINT8
*) UpdatingVariable
, VariableSize
);
674 CurrPtr
+= VariableSize
;
678 // Reinstall all in delete transition variables
680 Variable
= GetStartPointer (VariableStoreHeader
);
681 while (IsValidVariableHeader (Variable
)) {
682 NextVariable
= GetNextVariablePtr (Variable
);
683 if (Variable
!= UpdatingVariable
&& Variable
->State
== (VAR_IN_DELETED_TRANSITION
& VAR_ADDED
)) {
686 // Buffer has cached all ADDED variable.
687 // Per IN_DELETED variable, we have to guarantee that
688 // no ADDED one in previous buffer.
692 AddedVariable
= GetStartPointer ((VARIABLE_STORE_HEADER
*) ValidBuffer
);
693 while (IsValidVariableHeader (AddedVariable
)) {
694 NextAddedVariable
= GetNextVariablePtr (AddedVariable
);
695 NameSize
= NameSizeOfVariable (AddedVariable
);
696 if (CompareGuid (&AddedVariable
->VendorGuid
, &Variable
->VendorGuid
) &&
697 NameSize
== NameSizeOfVariable (Variable
)
699 Point0
= (VOID
*) GetVariableNamePtr (AddedVariable
);
700 Point1
= (VOID
*) GetVariableNamePtr (Variable
);
701 if (CompareMem (Point0
, Point1
, NameSizeOfVariable (AddedVariable
)) == 0) {
706 AddedVariable
= NextAddedVariable
;
710 // Promote VAR_IN_DELETED_TRANSITION to VAR_ADDED
712 VariableSize
= (UINTN
) NextVariable
- (UINTN
) Variable
;
713 CopyMem (CurrPtr
, (UINT8
*) Variable
, VariableSize
);
714 ((VARIABLE_HEADER
*) CurrPtr
)->State
= VAR_ADDED
;
715 CurrPtr
+= VariableSize
;
719 Variable
= NextVariable
;
724 // If volatile variable store, just copy valid buffer
726 SetMem ((UINT8
*) (UINTN
) VariableBase
, VariableStoreHeader
->Size
, 0xff);
727 CopyMem ((UINT8
*) (UINTN
) VariableBase
, ValidBuffer
, (UINTN
) (CurrPtr
- (UINT8
*) ValidBuffer
));
728 Status
= EFI_SUCCESS
;
731 // If non-volatile variable store, perform FTW here.
733 Status
= FtwVariableSpace (
736 (UINTN
) (CurrPtr
- (UINT8
*) ValidBuffer
)
739 if (!EFI_ERROR (Status
)) {
740 *LastVariableOffset
= (UINTN
) (CurrPtr
- (UINT8
*) ValidBuffer
);
742 *LastVariableOffset
= 0;
745 FreePool (ValidBuffer
);
752 Update the Cache with Variable information. These are the same
753 arguments as the EFI Variable services.
755 @param[in] VariableName Name of variable
756 @param[in] VendorGuid Guid of variable
757 @param[in] Attributes Attribues of the variable
758 @param[in] DataSize Size of data. 0 means delete
759 @param[in] Data Variable data
763 UpdateVariableCache (
764 IN CHAR16
*VariableName
,
765 IN EFI_GUID
*VendorGuid
,
766 IN UINT32 Attributes
,
771 VARIABLE_CACHE_ENTRY
*Entry
;
774 if (EfiAtRuntime ()) {
776 // Don't use the cache at runtime
781 for (Index
= 0, Entry
= mVariableCache
; Index
< sizeof (mVariableCache
)/sizeof (VARIABLE_CACHE_ENTRY
); Index
++, Entry
++) {
782 if (CompareGuid (VendorGuid
, Entry
->Guid
)) {
783 if (StrCmp (VariableName
, Entry
->Name
) == 0) {
784 Entry
->Attributes
= Attributes
;
789 if (Entry
->DataSize
!= 0) {
790 FreePool (Entry
->Data
);
792 Entry
->DataSize
= DataSize
;
793 } else if (DataSize
== Entry
->DataSize
) {
794 CopyMem (Entry
->Data
, Data
, DataSize
);
796 Entry
->Data
= AllocatePool (DataSize
);
797 ASSERT (Entry
->Data
!= NULL
);
799 Entry
->DataSize
= DataSize
;
800 CopyMem (Entry
->Data
, Data
, DataSize
);
809 Search the cache to check if the variable is in it.
811 This function searches the variable cache. If the variable to find exists, return its data
814 @param VariableName A Null-terminated Unicode string that is the name of the vendor's
815 variable. Each VariableName is unique for each
817 @param VendorGuid A unique identifier for the vendor
818 @param Attributes Pointer to the attributes bitmask of the variable for output.
819 @param DataSize On input, size of the buffer of Data.
820 On output, size of the variable's data.
821 @param Data Pointer to the data buffer for output.
823 @retval EFI_SUCCESS VariableGuid & VariableName data was returned.
824 @retval EFI_NOT_FOUND No matching variable found in cache.
825 @retval EFI_BUFFER_TOO_SMALL *DataSize is smaller than size of the variable's data to return.
829 FindVariableInCache (
830 IN CHAR16
*VariableName
,
831 IN EFI_GUID
*VendorGuid
,
832 OUT UINT32
*Attributes OPTIONAL
,
833 IN OUT UINTN
*DataSize
,
837 VARIABLE_CACHE_ENTRY
*Entry
;
840 if (EfiAtRuntime ()) {
841 // Don't use the cache at runtime
842 return EFI_NOT_FOUND
;
845 for (Index
= 0, Entry
= mVariableCache
; Index
< sizeof (mVariableCache
)/sizeof (VARIABLE_CACHE_ENTRY
); Index
++, Entry
++) {
846 if (CompareGuid (VendorGuid
, Entry
->Guid
)) {
847 if (StrCmp (VariableName
, Entry
->Name
) == 0) {
848 if (Entry
->DataSize
== 0) {
849 // Variable was deleted so return not found
850 return EFI_NOT_FOUND
;
851 } else if (Entry
->DataSize
> *DataSize
) {
852 // If the buffer is too small return correct size
853 *DataSize
= Entry
->DataSize
;
854 return EFI_BUFFER_TOO_SMALL
;
856 *DataSize
= Entry
->DataSize
;
858 CopyMem (Data
, Entry
->Data
, Entry
->DataSize
);
859 if (Attributes
!= NULL
) {
860 *Attributes
= Entry
->Attributes
;
868 return EFI_NOT_FOUND
;
872 Finds variable in storage blocks of volatile and non-volatile storage areas.
874 This code finds variable in storage blocks of volatile and non-volatile storage areas.
875 If VariableName is an empty string, then we just return the first
876 qualified variable without comparing VariableName and VendorGuid.
877 Otherwise, VariableName and VendorGuid are compared.
879 @param VariableName Name of the variable to be found
880 @param VendorGuid Vendor GUID to be found.
881 @param PtrTrack VARIABLE_POINTER_TRACK structure for output,
882 including the range searched and the target position.
883 @param Global Pointer to VARIABLE_GLOBAL structure, including
884 base of volatile variable storage area, base of
885 NV variable storage area, and a lock.
887 @retval EFI_INVALID_PARAMETER If VariableName is not an empty string, while
889 @retval EFI_SUCCESS Variable successfully found
890 @retval EFI_INVALID_PARAMETER Variable not found
895 IN CHAR16
*VariableName
,
896 IN EFI_GUID
*VendorGuid
,
897 OUT VARIABLE_POINTER_TRACK
*PtrTrack
,
898 IN VARIABLE_GLOBAL
*Global
901 VARIABLE_HEADER
*Variable
[2];
902 VARIABLE_HEADER
*InDeletedVariable
;
903 VARIABLE_STORE_HEADER
*VariableStoreHeader
[2];
904 UINTN InDeletedStorageIndex
;
909 // 0: Volatile, 1: Non-Volatile
910 // The index and attributes mapping must be kept in this order as RuntimeServiceGetNextVariableName
911 // make use of this mapping to implement search algorithme.
913 VariableStoreHeader
[0] = (VARIABLE_STORE_HEADER
*) ((UINTN
) mVariableModuleGlobal
->VariableGlobal
.VolatileVariableBase
);
914 VariableStoreHeader
[1] = (VARIABLE_STORE_HEADER
*) ((UINTN
) mVariableModuleGlobal
->VariableGlobal
.NonVolatileVariableBase
);
917 // Start Pointers for the variable.
918 // Actual Data Pointer where data can be written.
920 Variable
[0] = GetStartPointer (VariableStoreHeader
[0]);
921 Variable
[1] = GetStartPointer (VariableStoreHeader
[1]);
923 if (VariableName
[0] != 0 && VendorGuid
== NULL
) {
924 return EFI_INVALID_PARAMETER
;
928 // Find the variable by walk through volatile and then non-volatile variable store
930 InDeletedVariable
= NULL
;
931 InDeletedStorageIndex
= 0;
932 for (Index
= 0; Index
< 2; Index
++) {
933 while (IsValidVariableHeader (Variable
[Index
]) && (Variable
[Index
] <= GetEndPointer (VariableStoreHeader
[Index
]))) {
934 if (Variable
[Index
]->State
== VAR_ADDED
||
935 Variable
[Index
]->State
== (VAR_IN_DELETED_TRANSITION
& VAR_ADDED
)
937 if (!EfiAtRuntime () || ((Variable
[Index
]->Attributes
& EFI_VARIABLE_RUNTIME_ACCESS
) != 0)) {
938 if (VariableName
[0] == 0) {
939 if (Variable
[Index
]->State
== (VAR_IN_DELETED_TRANSITION
& VAR_ADDED
)) {
940 InDeletedVariable
= Variable
[Index
];
941 InDeletedStorageIndex
= Index
;
943 PtrTrack
->StartPtr
= GetStartPointer (VariableStoreHeader
[Index
]);
944 PtrTrack
->EndPtr
= GetEndPointer (VariableStoreHeader
[Index
]);
945 PtrTrack
->CurrPtr
= Variable
[Index
];
946 PtrTrack
->Volatile
= (BOOLEAN
)(Index
== 0);
951 if (CompareGuid (VendorGuid
, &Variable
[Index
]->VendorGuid
)) {
952 Point
= (VOID
*) GetVariableNamePtr (Variable
[Index
]);
954 ASSERT (NameSizeOfVariable (Variable
[Index
]) != 0);
955 if (CompareMem (VariableName
, Point
, NameSizeOfVariable (Variable
[Index
])) == 0) {
956 if (Variable
[Index
]->State
== (VAR_IN_DELETED_TRANSITION
& VAR_ADDED
)) {
957 InDeletedVariable
= Variable
[Index
];
958 InDeletedStorageIndex
= Index
;
960 PtrTrack
->StartPtr
= GetStartPointer (VariableStoreHeader
[Index
]);
961 PtrTrack
->EndPtr
= GetEndPointer (VariableStoreHeader
[Index
]);
962 PtrTrack
->CurrPtr
= Variable
[Index
];
963 PtrTrack
->Volatile
= (BOOLEAN
)(Index
== 0);
973 Variable
[Index
] = GetNextVariablePtr (Variable
[Index
]);
975 if (InDeletedVariable
!= NULL
) {
976 PtrTrack
->StartPtr
= GetStartPointer (VariableStoreHeader
[InDeletedStorageIndex
]);
977 PtrTrack
->EndPtr
= GetEndPointer (VariableStoreHeader
[InDeletedStorageIndex
]);
978 PtrTrack
->CurrPtr
= InDeletedVariable
;
979 PtrTrack
->Volatile
= (BOOLEAN
)(InDeletedStorageIndex
== 0);
983 PtrTrack
->CurrPtr
= NULL
;
984 return EFI_NOT_FOUND
;
990 This code finds variable in storage blocks (Volatile or Non-Volatile).
992 @param VariableName Name of Variable to be found.
993 @param VendorGuid Variable vendor GUID.
994 @param Attributes Attribute value of the variable found.
995 @param DataSize Size of Data found. If size is less than the
996 data, this value contains the required size.
997 @param Data Data pointer.
999 @return EFI_INVALID_PARAMETER Invalid parameter
1000 @return EFI_SUCCESS Find the specified variable
1001 @return EFI_NOT_FOUND Not found
1002 @return EFI_BUFFER_TO_SMALL DataSize is too small for the result
1007 RuntimeServiceGetVariable (
1008 IN CHAR16
*VariableName
,
1009 IN EFI_GUID
*VendorGuid
,
1010 OUT UINT32
*Attributes OPTIONAL
,
1011 IN OUT UINTN
*DataSize
,
1016 VARIABLE_POINTER_TRACK Variable
;
1019 if (VariableName
== NULL
|| VendorGuid
== NULL
|| DataSize
== NULL
) {
1020 return EFI_INVALID_PARAMETER
;
1023 AcquireLockOnlyAtBootTime(&mVariableModuleGlobal
->VariableGlobal
.VariableServicesLock
);
1026 // Find existing variable
1028 Status
= FindVariableInCache (VariableName
, VendorGuid
, Attributes
, DataSize
, Data
);
1029 if ((Status
== EFI_BUFFER_TOO_SMALL
) || (Status
== EFI_SUCCESS
)){
1031 UpdateVariableInfo (VariableName
, VendorGuid
, FALSE
, TRUE
, FALSE
, FALSE
, TRUE
);
1035 Status
= FindVariable (VariableName
, VendorGuid
, &Variable
, &mVariableModuleGlobal
->VariableGlobal
);
1036 if (Variable
.CurrPtr
== NULL
|| EFI_ERROR (Status
)) {
1043 VarDataSize
= DataSizeOfVariable (Variable
.CurrPtr
);
1044 ASSERT (VarDataSize
!= 0);
1046 if (*DataSize
>= VarDataSize
) {
1048 Status
= EFI_INVALID_PARAMETER
;
1052 CopyMem (Data
, GetVariableDataPtr (Variable
.CurrPtr
), VarDataSize
);
1053 if (Attributes
!= NULL
) {
1054 *Attributes
= Variable
.CurrPtr
->Attributes
;
1057 *DataSize
= VarDataSize
;
1058 UpdateVariableInfo (VariableName
, VendorGuid
, Variable
.Volatile
, TRUE
, FALSE
, FALSE
, FALSE
);
1059 UpdateVariableCache (VariableName
, VendorGuid
, Variable
.CurrPtr
->Attributes
, VarDataSize
, Data
);
1061 Status
= EFI_SUCCESS
;
1064 *DataSize
= VarDataSize
;
1065 Status
= EFI_BUFFER_TOO_SMALL
;
1070 ReleaseLockOnlyAtBootTime (&mVariableModuleGlobal
->VariableGlobal
.VariableServicesLock
);
1078 This code Finds the Next available variable.
1080 @param VariableNameSize Size of the variable name
1081 @param VariableName Pointer to variable name
1082 @param VendorGuid Variable Vendor Guid
1084 @return EFI_INVALID_PARAMETER Invalid parameter
1085 @return EFI_SUCCESS Find the specified variable
1086 @return EFI_NOT_FOUND Not found
1087 @return EFI_BUFFER_TO_SMALL DataSize is too small for the result
1092 RuntimeServiceGetNextVariableName (
1093 IN OUT UINTN
*VariableNameSize
,
1094 IN OUT CHAR16
*VariableName
,
1095 IN OUT EFI_GUID
*VendorGuid
1098 VARIABLE_POINTER_TRACK Variable
;
1102 if (VariableNameSize
== NULL
|| VariableName
== NULL
|| VendorGuid
== NULL
) {
1103 return EFI_INVALID_PARAMETER
;
1106 AcquireLockOnlyAtBootTime(&mVariableModuleGlobal
->VariableGlobal
.VariableServicesLock
);
1108 Status
= FindVariable (VariableName
, VendorGuid
, &Variable
, &mVariableModuleGlobal
->VariableGlobal
);
1109 if (Variable
.CurrPtr
== NULL
|| EFI_ERROR (Status
)) {
1113 if (VariableName
[0] != 0) {
1115 // If variable name is not NULL, get next variable
1117 Variable
.CurrPtr
= GetNextVariablePtr (Variable
.CurrPtr
);
1122 // If both volatile and non-volatile variable store are parsed,
1125 if (Variable
.CurrPtr
>= Variable
.EndPtr
|| Variable
.CurrPtr
== NULL
) {
1126 Variable
.Volatile
= (BOOLEAN
) (Variable
.Volatile
^ ((BOOLEAN
) 0x1));
1127 if (!Variable
.Volatile
) {
1128 Variable
.StartPtr
= GetStartPointer ((VARIABLE_STORE_HEADER
*) (UINTN
) mVariableModuleGlobal
->VariableGlobal
.NonVolatileVariableBase
);
1129 Variable
.EndPtr
= GetEndPointer ((VARIABLE_STORE_HEADER
*) ((UINTN
) mVariableModuleGlobal
->VariableGlobal
.NonVolatileVariableBase
));
1131 Status
= EFI_NOT_FOUND
;
1135 Variable
.CurrPtr
= Variable
.StartPtr
;
1136 if (!IsValidVariableHeader (Variable
.CurrPtr
)) {
1141 // Variable is found
1143 if (IsValidVariableHeader (Variable
.CurrPtr
) && Variable
.CurrPtr
->State
== VAR_ADDED
) {
1144 if ((EfiAtRuntime () && ((Variable
.CurrPtr
->Attributes
& EFI_VARIABLE_RUNTIME_ACCESS
) == 0)) == 0) {
1145 VarNameSize
= NameSizeOfVariable (Variable
.CurrPtr
);
1146 ASSERT (VarNameSize
!= 0);
1148 if (VarNameSize
<= *VariableNameSize
) {
1151 GetVariableNamePtr (Variable
.CurrPtr
),
1156 &Variable
.CurrPtr
->VendorGuid
,
1159 Status
= EFI_SUCCESS
;
1161 Status
= EFI_BUFFER_TOO_SMALL
;
1164 *VariableNameSize
= VarNameSize
;
1169 Variable
.CurrPtr
= GetNextVariablePtr (Variable
.CurrPtr
);
1173 ReleaseLockOnlyAtBootTime (&mVariableModuleGlobal
->VariableGlobal
.VariableServicesLock
);
1179 This code sets variable in storage blocks (Volatile or Non-Volatile).
1181 @param VariableName Name of Variable to be found
1182 @param VendorGuid Variable vendor GUID
1183 @param Attributes Attribute value of the variable found
1184 @param DataSize Size of Data found. If size is less than the
1185 data, this value contains the required size.
1186 @param Data Data pointer
1188 @return EFI_INVALID_PARAMETER Invalid parameter
1189 @return EFI_SUCCESS Set successfully
1190 @return EFI_OUT_OF_RESOURCES Resource not enough to set variable
1191 @return EFI_NOT_FOUND Not found
1192 @return EFI_WRITE_PROTECTED Variable is read-only
1197 RuntimeServiceSetVariable (
1198 IN CHAR16
*VariableName
,
1199 IN EFI_GUID
*VendorGuid
,
1200 IN UINT32 Attributes
,
1205 VARIABLE_POINTER_TRACK Variable
;
1207 VARIABLE_HEADER
*NextVariable
;
1209 UINTN VarNameOffset
;
1210 UINTN VarDataOffset
;
1214 UINTN
*VolatileOffset
;
1215 UINTN
*NonVolatileOffset
;
1216 EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*Fvb
;
1218 EFI_PHYSICAL_ADDRESS Point
;
1221 // Check input parameters
1223 if (VariableName
== NULL
|| VariableName
[0] == 0 || VendorGuid
== NULL
) {
1224 return EFI_INVALID_PARAMETER
;
1227 // Make sure if runtime bit is set, boot service bit is set also
1229 if ((Attributes
& (EFI_VARIABLE_RUNTIME_ACCESS
| EFI_VARIABLE_BOOTSERVICE_ACCESS
)) == EFI_VARIABLE_RUNTIME_ACCESS
) {
1230 return EFI_INVALID_PARAMETER
;
1234 // The size of the VariableName, including the Unicode Null in bytes plus
1235 // the DataSize is limited to maximum size of FixedPcdGet32(PcdMaxHardwareErrorVariableSize)
1236 // bytes for HwErrRec, and FixedPcdGet32(PcdMaxVariableSize) bytes for the others.
1238 if ((Attributes
& EFI_VARIABLE_HARDWARE_ERROR_RECORD
) == EFI_VARIABLE_HARDWARE_ERROR_RECORD
) {
1239 if ((DataSize
> FixedPcdGet32(PcdMaxHardwareErrorVariableSize
)) ||
1240 (sizeof (VARIABLE_HEADER
) + StrSize (VariableName
) + DataSize
> FixedPcdGet32(PcdMaxHardwareErrorVariableSize
))) {
1241 return EFI_INVALID_PARAMETER
;
1245 // The size of the VariableName, including the Unicode Null in bytes plus
1246 // the DataSize is limited to maximum size of FixedPcdGet32(PcdMaxVariableSize) bytes.
1248 if ((DataSize
> FixedPcdGet32(PcdMaxVariableSize
)) ||
1249 (sizeof (VARIABLE_HEADER
) + StrSize (VariableName
) + DataSize
> FixedPcdGet32(PcdMaxVariableSize
))) {
1250 return EFI_INVALID_PARAMETER
;
1254 AcquireLockOnlyAtBootTime(&mVariableModuleGlobal
->VariableGlobal
.VariableServicesLock
);
1257 Fvb
= mVariableModuleGlobal
->FvbInstance
;
1258 VolatileOffset
= &mVariableModuleGlobal
->VolatileLastVariableOffset
;
1261 // Consider reentrant in MCA/INIT/NMI. It needs be reupdated;
1263 if (1 < InterlockedIncrement (&mVariableModuleGlobal
->VariableGlobal
.ReentrantState
)) {
1264 Point
= mVariableModuleGlobal
->VariableGlobal
.NonVolatileVariableBase
;;
1266 // Parse non-volatile variable data and get last variable offset
1268 NextVariable
= GetStartPointer ((VARIABLE_STORE_HEADER
*) (UINTN
) Point
);
1269 while (IsValidVariableHeader (NextVariable
)) {
1270 NextVariable
= GetNextVariablePtr (NextVariable
);
1272 mVariableModuleGlobal
->NonVolatileLastVariableOffset
= (UINTN
) NextVariable
- (UINTN
) Point
;
1275 NonVolatileOffset
= &mVariableModuleGlobal
->NonVolatileLastVariableOffset
;
1279 // Check whether the input variable is already existed
1282 Status
= FindVariable (VariableName
, VendorGuid
, &Variable
, &mVariableModuleGlobal
->VariableGlobal
);
1283 if (Status
== EFI_SUCCESS
&& Variable
.CurrPtr
!= NULL
) {
1285 // Update/Delete existing variable
1287 Volatile
= Variable
.Volatile
;
1289 if (EfiAtRuntime ()) {
1291 // If EfiAtRuntime and the variable is Volatile and Runtime Access,
1292 // the volatile is ReadOnly, and SetVariable should be aborted and
1293 // return EFI_WRITE_PROTECTED.
1295 if (Variable
.Volatile
) {
1296 Status
= EFI_WRITE_PROTECTED
;
1300 // Only variable have NV attribute can be updated/deleted in Runtime
1302 if ((Variable
.CurrPtr
->Attributes
& EFI_VARIABLE_NON_VOLATILE
) == 0) {
1303 Status
= EFI_INVALID_PARAMETER
;
1308 // Setting a data variable with no access, or zero DataSize attributes
1309 // specified causes it to be deleted.
1311 if (DataSize
== 0 || (Attributes
& (EFI_VARIABLE_RUNTIME_ACCESS
| EFI_VARIABLE_BOOTSERVICE_ACCESS
)) == 0) {
1312 State
= Variable
.CurrPtr
->State
;
1313 State
&= VAR_DELETED
;
1315 Status
= UpdateVariableStore (
1316 &mVariableModuleGlobal
->VariableGlobal
,
1320 (UINTN
) &Variable
.CurrPtr
->State
,
1324 if (!EFI_ERROR (Status
)) {
1325 UpdateVariableInfo (VariableName
, VendorGuid
, Volatile
, FALSE
, FALSE
, TRUE
, FALSE
);
1326 UpdateVariableCache (VariableName
, VendorGuid
, Attributes
, DataSize
, Data
);
1331 // If the variable is marked valid and the same data has been passed in
1332 // then return to the caller immediately.
1334 if (DataSizeOfVariable (Variable
.CurrPtr
) == DataSize
&&
1335 (CompareMem (Data
, GetVariableDataPtr (Variable
.CurrPtr
), DataSize
) == 0)) {
1337 UpdateVariableInfo (VariableName
, VendorGuid
, Volatile
, FALSE
, TRUE
, FALSE
, FALSE
);
1338 Status
= EFI_SUCCESS
;
1340 } else if ((Variable
.CurrPtr
->State
== VAR_ADDED
) ||
1341 (Variable
.CurrPtr
->State
== (VAR_ADDED
& VAR_IN_DELETED_TRANSITION
))) {
1344 // Mark the old variable as in delete transition
1346 State
= Variable
.CurrPtr
->State
;
1347 State
&= VAR_IN_DELETED_TRANSITION
;
1349 Status
= UpdateVariableStore (
1350 &mVariableModuleGlobal
->VariableGlobal
,
1354 (UINTN
) &Variable
.CurrPtr
->State
,
1358 if (EFI_ERROR (Status
)) {
1362 } else if (Status
== EFI_NOT_FOUND
) {
1364 // Create a new variable
1368 // Make sure we are trying to create a new variable.
1369 // Setting a data variable with no access, or zero DataSize attributes means to delete it.
1371 if (DataSize
== 0 || (Attributes
& (EFI_VARIABLE_RUNTIME_ACCESS
| EFI_VARIABLE_BOOTSERVICE_ACCESS
)) == 0) {
1372 Status
= EFI_NOT_FOUND
;
1377 // Only variable have NV|RT attribute can be created in Runtime
1379 if (EfiAtRuntime () &&
1380 (((Attributes
& EFI_VARIABLE_RUNTIME_ACCESS
) == 0) || ((Attributes
& EFI_VARIABLE_NON_VOLATILE
) == 0))) {
1381 Status
= EFI_INVALID_PARAMETER
;
1386 // Status should be EFI_INVALID_PARAMETER here according to return status of FindVariable().
1388 ASSERT (Status
== EFI_INVALID_PARAMETER
);
1393 // Function part - create a new variable and copy the data.
1394 // Both update a variable and create a variable will come here.
1396 // Tricky part: Use scratch data area at the end of volatile variable store
1397 // as a temporary storage.
1399 NextVariable
= GetEndPointer ((VARIABLE_STORE_HEADER
*) ((UINTN
) mVariableModuleGlobal
->VariableGlobal
.VolatileVariableBase
));
1401 SetMem (NextVariable
, FixedPcdGet32(PcdMaxVariableSize
), 0xff);
1403 NextVariable
->StartId
= VARIABLE_DATA
;
1404 NextVariable
->Attributes
= Attributes
;
1406 // NextVariable->State = VAR_ADDED;
1408 NextVariable
->Reserved
= 0;
1409 VarNameOffset
= sizeof (VARIABLE_HEADER
);
1410 VarNameSize
= StrSize (VariableName
);
1412 (UINT8
*) ((UINTN
) NextVariable
+ VarNameOffset
),
1416 VarDataOffset
= VarNameOffset
+ VarNameSize
+ GET_PAD_SIZE (VarNameSize
);
1418 (UINT8
*) ((UINTN
) NextVariable
+ VarDataOffset
),
1422 CopyMem (&NextVariable
->VendorGuid
, VendorGuid
, sizeof (EFI_GUID
));
1424 // There will be pad bytes after Data, the NextVariable->NameSize and
1425 // NextVariable->DataSize should not include pad size so that variable
1426 // service can get actual size in GetVariable
1428 NextVariable
->NameSize
= (UINT32
)VarNameSize
;
1429 NextVariable
->DataSize
= (UINT32
)DataSize
;
1432 // The actual size of the variable that stores in storage should
1433 // include pad size.
1435 VarSize
= VarDataOffset
+ DataSize
+ GET_PAD_SIZE (DataSize
);
1436 if ((Attributes
& EFI_VARIABLE_NON_VOLATILE
) != 0) {
1438 // Create a nonvolatile variable
1442 if ((UINT32
) (VarSize
+*NonVolatileOffset
) >
1443 ((VARIABLE_STORE_HEADER
*) ((UINTN
) (mVariableModuleGlobal
->VariableGlobal
.NonVolatileVariableBase
)))->Size
1445 if (EfiAtRuntime ()) {
1446 Status
= EFI_OUT_OF_RESOURCES
;
1450 // Perform garbage collection & reclaim operation
1452 Status
= Reclaim (mVariableModuleGlobal
->VariableGlobal
.NonVolatileVariableBase
, NonVolatileOffset
, FALSE
, Variable
.CurrPtr
);
1453 if (EFI_ERROR (Status
)) {
1457 // If still no enough space, return out of resources
1459 if ((UINT32
) (VarSize
+*NonVolatileOffset
) >
1460 ((VARIABLE_STORE_HEADER
*) ((UINTN
) (mVariableModuleGlobal
->VariableGlobal
.NonVolatileVariableBase
)))->Size
1462 Status
= EFI_OUT_OF_RESOURCES
;
1470 // 1. Write variable header
1471 // 2. Set variable state to header valid
1472 // 3. Write variable data
1473 // 4. Set variable state to valid
1478 Status
= UpdateVariableStore (
1479 &mVariableModuleGlobal
->VariableGlobal
,
1484 sizeof (VARIABLE_HEADER
),
1485 (UINT8
*) NextVariable
1488 if (EFI_ERROR (Status
)) {
1495 NextVariable
->State
= VAR_HEADER_VALID_ONLY
;
1496 Status
= UpdateVariableStore (
1497 &mVariableModuleGlobal
->VariableGlobal
,
1502 sizeof (VARIABLE_HEADER
),
1503 (UINT8
*) NextVariable
1506 if (EFI_ERROR (Status
)) {
1512 Status
= UpdateVariableStore (
1513 &mVariableModuleGlobal
->VariableGlobal
,
1517 *NonVolatileOffset
+ sizeof (VARIABLE_HEADER
),
1518 (UINT32
) VarSize
- sizeof (VARIABLE_HEADER
),
1519 (UINT8
*) NextVariable
+ sizeof (VARIABLE_HEADER
)
1522 if (EFI_ERROR (Status
)) {
1528 NextVariable
->State
= VAR_ADDED
;
1529 Status
= UpdateVariableStore (
1530 &mVariableModuleGlobal
->VariableGlobal
,
1535 sizeof (VARIABLE_HEADER
),
1536 (UINT8
*) NextVariable
1539 if (EFI_ERROR (Status
)) {
1543 *NonVolatileOffset
= HEADER_ALIGN (*NonVolatileOffset
+ VarSize
);
1547 // Create a volatile variable
1551 if ((UINT32
) (VarSize
+*VolatileOffset
) >
1552 ((VARIABLE_STORE_HEADER
*) ((UINTN
) (mVariableModuleGlobal
->VariableGlobal
.VolatileVariableBase
)))->Size
) {
1554 // Perform garbage collection & reclaim operation
1556 Status
= Reclaim (mVariableModuleGlobal
->VariableGlobal
.VolatileVariableBase
, VolatileOffset
, TRUE
, Variable
.CurrPtr
);
1557 if (EFI_ERROR (Status
)) {
1561 // If still no enough space, return out of resources
1563 if ((UINT32
) (VarSize
+*VolatileOffset
) >
1564 ((VARIABLE_STORE_HEADER
*) ((UINTN
) (mVariableModuleGlobal
->VariableGlobal
.VolatileVariableBase
)))->Size
1566 Status
= EFI_OUT_OF_RESOURCES
;
1573 NextVariable
->State
= VAR_ADDED
;
1574 Status
= UpdateVariableStore (
1575 &mVariableModuleGlobal
->VariableGlobal
,
1581 (UINT8
*) NextVariable
1584 if (EFI_ERROR (Status
)) {
1588 *VolatileOffset
= HEADER_ALIGN (*VolatileOffset
+ VarSize
);
1591 // Mark the old variable as deleted
1593 if (!Reclaimed
&& !EFI_ERROR (Status
) && Variable
.CurrPtr
!= NULL
) {
1594 State
= Variable
.CurrPtr
->State
;
1595 State
&= VAR_DELETED
;
1597 Status
= UpdateVariableStore (
1598 &mVariableModuleGlobal
->VariableGlobal
,
1602 (UINTN
) &Variable
.CurrPtr
->State
,
1607 if (!EFI_ERROR (Status
)) {
1608 UpdateVariableInfo (VariableName
, VendorGuid
, Volatile
, FALSE
, TRUE
, FALSE
, FALSE
);
1609 UpdateVariableCache (VariableName
, VendorGuid
, Attributes
, DataSize
, Data
);
1614 Status
= EFI_SUCCESS
;
1615 UpdateVariableInfo (VariableName
, VendorGuid
, Volatile
, FALSE
, TRUE
, FALSE
, FALSE
);
1616 UpdateVariableCache (VariableName
, VendorGuid
, Attributes
, DataSize
, Data
);
1619 InterlockedDecrement (&mVariableModuleGlobal
->VariableGlobal
.ReentrantState
);
1620 ReleaseLockOnlyAtBootTime (&mVariableModuleGlobal
->VariableGlobal
.VariableServicesLock
);
1627 This code returns information about the EFI variables.
1629 @param Attributes Attributes bitmask to specify the type of variables
1630 on which to return information.
1631 @param MaximumVariableStorageSize Pointer to the maximum size of the storage space available
1632 for the EFI variables associated with the attributes specified.
1633 @param RemainingVariableStorageSize Pointer to the remaining size of the storage space available
1634 for EFI variables associated with the attributes specified.
1635 @param MaximumVariableSize Pointer to the maximum size of an individual EFI variables
1636 associated with the attributes specified.
1638 @return EFI_INVALID_PARAMETER An invalid combination of attribute bits was supplied.
1639 @return EFI_SUCCESS Query successfully.
1640 @return EFI_UNSUPPORTED The attribute is not supported on this platform.
1645 RuntimeServiceQueryVariableInfo (
1646 IN UINT32 Attributes
,
1647 OUT UINT64
*MaximumVariableStorageSize
,
1648 OUT UINT64
*RemainingVariableStorageSize
,
1649 OUT UINT64
*MaximumVariableSize
1652 VARIABLE_HEADER
*Variable
;
1653 VARIABLE_HEADER
*NextVariable
;
1654 UINT64 VariableSize
;
1655 VARIABLE_STORE_HEADER
*VariableStoreHeader
;
1657 if(MaximumVariableStorageSize
== NULL
|| RemainingVariableStorageSize
== NULL
|| MaximumVariableSize
== NULL
|| Attributes
== 0) {
1658 return EFI_INVALID_PARAMETER
;
1661 if((Attributes
& (EFI_VARIABLE_NON_VOLATILE
| EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_RUNTIME_ACCESS
| EFI_VARIABLE_HARDWARE_ERROR_RECORD
)) == 0) {
1663 // Make sure the Attributes combination is supported by the platform.
1665 return EFI_UNSUPPORTED
;
1666 } else if ((Attributes
& (EFI_VARIABLE_RUNTIME_ACCESS
| EFI_VARIABLE_BOOTSERVICE_ACCESS
)) == EFI_VARIABLE_RUNTIME_ACCESS
) {
1668 // Make sure if runtime bit is set, boot service bit is set also.
1670 return EFI_INVALID_PARAMETER
;
1671 } else if (EfiAtRuntime () && ((Attributes
& EFI_VARIABLE_RUNTIME_ACCESS
) == 0)) {
1673 // Make sure RT Attribute is set if we are in Runtime phase.
1675 return EFI_INVALID_PARAMETER
;
1678 AcquireLockOnlyAtBootTime(&mVariableModuleGlobal
->VariableGlobal
.VariableServicesLock
);
1680 if((Attributes
& EFI_VARIABLE_NON_VOLATILE
) == 0) {
1682 // Query is Volatile related.
1684 VariableStoreHeader
= (VARIABLE_STORE_HEADER
*) ((UINTN
) mVariableModuleGlobal
->VariableGlobal
.VolatileVariableBase
);
1687 // Query is Non-Volatile related.
1689 VariableStoreHeader
= (VARIABLE_STORE_HEADER
*) ((UINTN
) mVariableModuleGlobal
->VariableGlobal
.NonVolatileVariableBase
);
1693 // Now let's fill *MaximumVariableStorageSize *RemainingVariableStorageSize
1694 // with the storage size (excluding the storage header size).
1696 *MaximumVariableStorageSize
= VariableStoreHeader
->Size
- sizeof (VARIABLE_STORE_HEADER
);
1697 *RemainingVariableStorageSize
= VariableStoreHeader
->Size
- sizeof (VARIABLE_STORE_HEADER
);
1700 // Let *MaximumVariableSize be FixedPcdGet32(PcdMaxVariableSize) with the exception of the variable header size.
1702 *MaximumVariableSize
= FixedPcdGet32(PcdMaxVariableSize
) - sizeof (VARIABLE_HEADER
);
1705 // Harware error record variable needs larger size.
1707 if ((Attributes
& EFI_VARIABLE_HARDWARE_ERROR_RECORD
) == EFI_VARIABLE_HARDWARE_ERROR_RECORD
) {
1708 *MaximumVariableSize
= FixedPcdGet32(PcdMaxHardwareErrorVariableSize
) - sizeof (VARIABLE_HEADER
);
1712 // Point to the starting address of the variables.
1714 Variable
= GetStartPointer (VariableStoreHeader
);
1717 // Now walk through the related variable store.
1719 while (IsValidVariableHeader (Variable
) && (Variable
< GetEndPointer (VariableStoreHeader
))) {
1720 NextVariable
= GetNextVariablePtr (Variable
);
1721 VariableSize
= (UINT64
) (UINTN
) NextVariable
- (UINT64
) (UINTN
) Variable
;
1723 if (EfiAtRuntime ()) {
1725 // we don't take the state of the variables in mind
1726 // when calculating RemainingVariableStorageSize,
1727 // since the space occupied by variables not marked with
1728 // VAR_ADDED is not allowed to be reclaimed in Runtime.
1730 *RemainingVariableStorageSize
-= VariableSize
;
1733 // Only care about Variables with State VAR_ADDED,because
1734 // the space not marked as VAR_ADDED is reclaimable now.
1736 if (Variable
->State
== VAR_ADDED
) {
1737 *RemainingVariableStorageSize
-= VariableSize
;
1742 // Go to the next one
1744 Variable
= NextVariable
;
1747 if (*RemainingVariableStorageSize
< sizeof (VARIABLE_HEADER
)) {
1748 *MaximumVariableSize
= 0;
1749 } else if ((*RemainingVariableStorageSize
- sizeof (VARIABLE_HEADER
)) < *MaximumVariableSize
) {
1750 *MaximumVariableSize
= *RemainingVariableStorageSize
- sizeof (VARIABLE_HEADER
);
1753 ReleaseLockOnlyAtBootTime (&mVariableModuleGlobal
->VariableGlobal
.VariableServicesLock
);
1759 Notification function of EVT_GROUP_READY_TO_BOOT event group.
1761 This is a notification function registered on EVT_GROUP_READY_TO_BOOT event group.
1762 When the Boot Manager is about to load and execute a boot option, it reclaims variable
1763 storage if free size is below the threshold.
1765 @param Event Event whose notification function is being invoked
1766 @param Context Pointer to the notification function's context
1779 VarSize
= ((VARIABLE_STORE_HEADER
*) ((UINTN
) mVariableModuleGlobal
->VariableGlobal
.NonVolatileVariableBase
))->Size
;
1780 Status
= EFI_SUCCESS
;
1783 // Check if the free area is blow a threshold
1785 if ((VarSize
- mVariableModuleGlobal
->NonVolatileLastVariableOffset
) < VARIABLE_RECLAIM_THRESHOLD
) {
1787 mVariableModuleGlobal
->VariableGlobal
.NonVolatileVariableBase
,
1788 &mVariableModuleGlobal
->NonVolatileLastVariableOffset
,
1792 ASSERT_EFI_ERROR (Status
);
1797 Initializes variable store area for non-volatile and volatile variable.
1799 @param SystemTable The pointer of EFI_SYSTEM_TABLE.
1801 @retval EFI_SUCCESS Function successfully executed.
1802 @retval EFI_OUT_OF_RESOURCES Fail to allocate enough memory resource.
1806 VariableCommonInitialize (
1807 IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*FvbProtocol
1811 VARIABLE_STORE_HEADER
*VolatileVariableStore
;
1812 VARIABLE_STORE_HEADER
*VariableStoreHeader
;
1813 VARIABLE_HEADER
*NextVariable
;
1814 EFI_PHYSICAL_ADDRESS TempVariableStoreHeader
;
1815 EFI_GCD_MEMORY_SPACE_DESCRIPTOR GcdDescriptor
;
1816 EFI_PHYSICAL_ADDRESS BaseAddress
;
1820 EFI_PHYSICAL_ADDRESS VariableStoreBase
;
1821 UINT64 VariableStoreLength
;
1822 EFI_EVENT ReadyToBootEvent
;
1824 Status
= EFI_SUCCESS
;
1826 // Allocate runtime memory for variable driver global structure.
1828 mVariableModuleGlobal
= AllocateRuntimePool (sizeof (VARIABLE_MODULE_GLOBAL
));
1829 if (mVariableModuleGlobal
== NULL
) {
1830 return EFI_OUT_OF_RESOURCES
;
1833 EfiInitializeLock(&mVariableModuleGlobal
->VariableGlobal
.VariableServicesLock
, TPL_NOTIFY
);
1834 mVariableModuleGlobal
->VariableGlobal
.ReentrantState
= 0;
1837 // Allocate memory for volatile variable store
1839 VolatileVariableStore
= AllocateRuntimePool (FixedPcdGet32(PcdVariableStoreSize
) + FixedPcdGet32(PcdMaxVariableSize
));
1840 if (VolatileVariableStore
== NULL
) {
1841 FreePool (mVariableModuleGlobal
);
1842 return EFI_OUT_OF_RESOURCES
;
1845 SetMem (VolatileVariableStore
, FixedPcdGet32(PcdVariableStoreSize
) + FixedPcdGet32(PcdMaxVariableSize
), 0xff);
1848 // Variable Specific Data
1850 mVariableModuleGlobal
->VariableGlobal
.VolatileVariableBase
= (EFI_PHYSICAL_ADDRESS
) (UINTN
) VolatileVariableStore
;
1851 mVariableModuleGlobal
->VolatileLastVariableOffset
= (UINTN
) GetStartPointer (VolatileVariableStore
) - (UINTN
) VolatileVariableStore
;
1852 mVariableModuleGlobal
->FvbInstance
= FvbProtocol
;
1854 CopyGuid (&VolatileVariableStore
->Signature
, &gEfiVariableGuid
);
1855 VolatileVariableStore
->Size
= FixedPcdGet32(PcdVariableStoreSize
);
1856 VolatileVariableStore
->Format
= VARIABLE_STORE_FORMATTED
;
1857 VolatileVariableStore
->State
= VARIABLE_STORE_HEALTHY
;
1858 VolatileVariableStore
->Reserved
= 0;
1859 VolatileVariableStore
->Reserved1
= 0;
1862 // Get non volatile varaible store
1865 TempVariableStoreHeader
= (EFI_PHYSICAL_ADDRESS
) PcdGet32 (PcdFlashNvStorageVariableBase
);
1866 VariableStoreBase
= TempVariableStoreHeader
+ \
1867 (((EFI_FIRMWARE_VOLUME_HEADER
*)(UINTN
)(TempVariableStoreHeader
)) -> HeaderLength
);
1868 VariableStoreLength
= (UINT64
) PcdGet32 (PcdFlashNvStorageVariableSize
) - \
1869 (((EFI_FIRMWARE_VOLUME_HEADER
*)(UINTN
)(TempVariableStoreHeader
)) -> HeaderLength
);
1871 // Mark the variable storage region of the FLASH as RUNTIME
1873 BaseAddress
= VariableStoreBase
& (~EFI_PAGE_MASK
);
1874 Length
= VariableStoreLength
+ (VariableStoreBase
- BaseAddress
);
1875 Length
= (Length
+ EFI_PAGE_SIZE
- 1) & (~EFI_PAGE_MASK
);
1877 Status
= gDS
->GetMemorySpaceDescriptor (BaseAddress
, &GcdDescriptor
);
1878 if (EFI_ERROR (Status
)) {
1882 Status
= gDS
->SetMemorySpaceAttributes (
1885 GcdDescriptor
.Attributes
| EFI_MEMORY_RUNTIME
1887 if (EFI_ERROR (Status
)) {
1891 // Get address of non volatile variable store base
1893 mVariableModuleGlobal
->VariableGlobal
.NonVolatileVariableBase
= VariableStoreBase
;
1894 VariableStoreHeader
= (VARIABLE_STORE_HEADER
*)(UINTN
)VariableStoreBase
;
1895 if (GetVariableStoreStatus (VariableStoreHeader
) == EfiValid
) {
1896 if (~VariableStoreHeader
->Size
== 0) {
1897 Status
= UpdateVariableStore (
1898 &mVariableModuleGlobal
->VariableGlobal
,
1901 mVariableModuleGlobal
->FvbInstance
,
1902 (UINTN
) &VariableStoreHeader
->Size
,
1904 (UINT8
*) &VariableStoreLength
1907 // As Variables are stored in NV storage, which are slow devices,such as flash.
1908 // Variable operation may skip checking variable program result to improve performance,
1909 // We can assume Variable program is OK through some check point.
1910 // Variable Store Size Setting should be the first Variable write operation,
1911 // We can assume all Read/Write is OK if we can set Variable store size successfully.
1912 // If write fail, we will assert here
1914 ASSERT(VariableStoreHeader
->Size
== VariableStoreLength
);
1916 if (EFI_ERROR (Status
)) {
1922 // Parse non-volatile variable data and get last variable offset
1924 NextVariable
= GetStartPointer ((VARIABLE_STORE_HEADER
*)(UINTN
)VariableStoreBase
);
1925 Status
= EFI_SUCCESS
;
1927 while (IsValidVariableHeader (NextVariable
)) {
1928 NextVariable
= GetNextVariablePtr (NextVariable
);
1931 mVariableModuleGlobal
->NonVolatileLastVariableOffset
= (UINTN
) NextVariable
- (UINTN
) VariableStoreBase
;
1934 // Check if the free area is really free.
1936 for (Index
= mVariableModuleGlobal
->NonVolatileLastVariableOffset
; Index
< VariableStoreHeader
->Size
; Index
++) {
1937 Data
= ((UINT8
*) (UINTN
) mVariableModuleGlobal
->VariableGlobal
.NonVolatileVariableBase
)[Index
];
1940 // There must be something wrong in variable store, do reclaim operation.
1943 mVariableModuleGlobal
->VariableGlobal
.NonVolatileVariableBase
,
1944 &mVariableModuleGlobal
->NonVolatileLastVariableOffset
,
1949 if (EFI_ERROR (Status
)) {
1958 // Register the event handling function to reclaim variable for OS usage.
1960 Status
= EfiCreateEventReadyToBootEx (
1967 Status
= EFI_VOLUME_CORRUPTED
;
1968 DEBUG((EFI_D_INFO
, "Variable Store header is corrupted\n"));
1972 if (EFI_ERROR (Status
)) {
1973 FreePool (mVariableModuleGlobal
);
1974 FreePool (VolatileVariableStore
);
1981 Notification function of EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE
1983 This is a notification function registered on EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE event.
1984 It convers pointer to new virtual address.
1986 @param Event Event whose notification function is being invoked
1987 @param Context Pointer to the notification function's context
1992 VariableClassAddressChangeEvent (
1997 EfiConvertPointer (0x0, (VOID
**) &mVariableModuleGlobal
->FvbInstance
->GetBlockSize
);
1998 EfiConvertPointer (0x0, (VOID
**) &mVariableModuleGlobal
->FvbInstance
->GetPhysicalAddress
);
1999 EfiConvertPointer (0x0, (VOID
**) &mVariableModuleGlobal
->FvbInstance
->GetAttributes
);
2000 EfiConvertPointer (0x0, (VOID
**) &mVariableModuleGlobal
->FvbInstance
->SetAttributes
);
2001 EfiConvertPointer (0x0, (VOID
**) &mVariableModuleGlobal
->FvbInstance
->Read
);
2002 EfiConvertPointer (0x0, (VOID
**) &mVariableModuleGlobal
->FvbInstance
->Write
);
2003 EfiConvertPointer (0x0, (VOID
**) &mVariableModuleGlobal
->FvbInstance
->EraseBlocks
);
2004 EfiConvertPointer (0x0, (VOID
**) &mVariableModuleGlobal
->FvbInstance
);
2007 (VOID
**) &mVariableModuleGlobal
->VariableGlobal
.NonVolatileVariableBase
2011 (VOID
**) &mVariableModuleGlobal
->VariableGlobal
.VolatileVariableBase
2013 EfiConvertPointer (0x0, (VOID
**) &mVariableModuleGlobal
);
2018 FvbNotificationEvent (
2024 EFI_HANDLE
*HandleBuffer
;
2025 EFI_HANDLE FvbHandle
;
2028 EFI_PHYSICAL_ADDRESS FvbBaseAddress
;
2029 EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*Fvb
;
2030 EFI_FIRMWARE_VOLUME_HEADER
*FwVolHeader
;
2031 EFI_FVB_ATTRIBUTES_2 Attributes
;
2032 EFI_SYSTEM_TABLE
*SystemTable
;
2033 EFI_PHYSICAL_ADDRESS NvStorageVariableBase
;
2035 SystemTable
= (EFI_SYSTEM_TABLE
*)Context
;
2040 // Locate all handles of Fvb protocol
2042 Status
= gBS
->LocateHandleBuffer (
2044 &gEfiFirmwareVolumeBlockProtocolGuid
,
2049 if (EFI_ERROR (Status
)) {
2054 // Get the FVB to access variable store
2056 for (Index
= 0; Index
< HandleCount
; Index
+= 1, Status
= EFI_NOT_FOUND
) {
2057 Status
= gBS
->HandleProtocol (
2058 HandleBuffer
[Index
],
2059 &gEfiFirmwareVolumeBlockProtocolGuid
,
2062 if (EFI_ERROR (Status
)) {
2063 Status
= EFI_NOT_FOUND
;
2068 // Ensure this FVB protocol supported Write operation.
2070 Status
= Fvb
->GetAttributes (Fvb
, &Attributes
);
2071 if (EFI_ERROR (Status
) || ((Attributes
& EFI_FVB2_WRITE_STATUS
) == 0)) {
2075 // Compare the address and select the right one
2077 Status
= Fvb
->GetPhysicalAddress (Fvb
, &FvbBaseAddress
);
2078 if (EFI_ERROR (Status
)) {
2082 FwVolHeader
= (EFI_FIRMWARE_VOLUME_HEADER
*) ((UINTN
) FvbBaseAddress
);
2083 NvStorageVariableBase
= (EFI_PHYSICAL_ADDRESS
) PcdGet32 (PcdFlashNvStorageVariableBase
);
2084 if ((NvStorageVariableBase
>= FvbBaseAddress
) && (NvStorageVariableBase
< (FvbBaseAddress
+ FwVolHeader
->FvLength
))) {
2085 FvbHandle
= HandleBuffer
[Index
];
2086 Status
= EFI_SUCCESS
;
2091 FreePool (HandleBuffer
);
2092 if (!EFI_ERROR (Status
)) {
2093 Status
= VariableCommonInitialize (Fvb
);
2094 ASSERT_EFI_ERROR (Status
);
2096 SystemTable
->RuntimeServices
->GetVariable
= RuntimeServiceGetVariable
;
2097 SystemTable
->RuntimeServices
->GetNextVariableName
= RuntimeServiceGetNextVariableName
;
2098 SystemTable
->RuntimeServices
->SetVariable
= RuntimeServiceSetVariable
;
2099 SystemTable
->RuntimeServices
->QueryVariableInfo
= RuntimeServiceQueryVariableInfo
;
2102 // Now install the Variable Runtime Architectural Protocol on a new handle
2104 Status
= gBS
->InstallMultipleProtocolInterfaces (
2106 &gEfiVariableArchProtocolGuid
, NULL
,
2107 &gEfiVariableWriteArchProtocolGuid
, NULL
,
2110 ASSERT_EFI_ERROR (Status
);
2112 Status
= gBS
->CreateEventEx (
2115 VariableClassAddressChangeEvent
,
2117 &gEfiEventVirtualAddressChangeGuid
,
2118 &mVirtualAddressChangeEvent
2120 ASSERT_EFI_ERROR (Status
);
2126 Variable Driver main entry point. The Variable driver places the 4 EFI
2127 runtime services in the EFI System Table and installs arch protocols
2128 for variable read and write services being availible. It also registers
2129 notification function for EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE event.
2131 @param[in] ImageHandle The firmware allocated handle for the EFI image.
2132 @param[in] SystemTable A pointer to the EFI System Table.
2134 @retval EFI_SUCCESS Variable service successfully initialized.
2139 VariableServiceInitialize (
2140 IN EFI_HANDLE ImageHandle
,
2141 IN EFI_SYSTEM_TABLE
*SystemTable
2145 // Register FvbNotificationEvent () notify function.
2147 EfiCreateProtocolNotifyEvent (
2148 &gEfiFirmwareVolumeBlockProtocolGuid
,
2150 FvbNotificationEvent
,
2151 (VOID
*)SystemTable
,