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 - 2008, 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
;
43 IN EFI_PHYSICAL_ADDRESS VariableBaseAddress
,
50 Acquires lock only at boot time. Simply returns at runtime.
52 This is a temperary function which will be removed when
53 EfiAcquireLock() in UefiLib can handle the call in UEFI
54 Runtimer driver in RT phase.
55 It calls EfiAcquireLock() at boot time, and simply returns
58 @param Lock A pointer to the lock to acquire
62 AcquireLockOnlyAtBootTime (
66 if (!EfiAtRuntime ()) {
67 EfiAcquireLock (Lock
);
72 Releases lock only at boot time. Simply returns at runtime.
74 This is a temperary function which will be removed when
75 EfiReleaseLock() in UefiLib can handle the call in UEFI
76 Runtimer driver in RT phase.
77 It calls EfiReleaseLock() at boot time, and simply returns
80 @param Lock A pointer to the lock to release
84 ReleaseLockOnlyAtBootTime (
88 if (!EfiAtRuntime ()) {
89 EfiReleaseLock (Lock
);
95 Routine used to track statistical information about variable usage.
96 The data is stored in the EFI system table so it can be accessed later.
97 VariableInfo.efi can dump out the table. Only Boot Services variable
98 accesses are tracked by this code. The PcdVariableCollectStatistics
99 build flag controls if this feature is enabled.
101 A read that hits in the cache will have Read and Cache true for
102 the transaction. Data is allocated by this routine, but never
105 @param[in] VariableName Name of the Variable to track
106 @param[in] VendorGuid Guid of the Variable to track
107 @param[in] Volatile TRUE if volatile FALSE if non-volatile
108 @param[in] Read TRUE if GetVariable() was called
109 @param[in] Write TRUE if SetVariable() was called
110 @param[in] Delete TRUE if deleted via SetVariable()
111 @param[in] Cache TRUE for a cache hit.
116 IN CHAR16
*VariableName
,
117 IN EFI_GUID
*VendorGuid
,
125 VARIABLE_INFO_ENTRY
*Entry
;
127 if (FeaturePcdGet (PcdVariableCollectStatistics
)) {
129 if (EfiAtRuntime ()) {
130 // Don't collect statistics at runtime
134 if (gVariableInfo
== NULL
) {
136 // on the first call allocate a entry and place a pointer to it in
137 // the EFI System Table
139 gVariableInfo
= AllocateZeroPool (sizeof (VARIABLE_INFO_ENTRY
));
140 ASSERT (gVariableInfo
!= NULL
);
142 CopyGuid (&gVariableInfo
->VendorGuid
, VendorGuid
);
143 gVariableInfo
->Name
= AllocatePool (StrLen (VariableName
));
144 ASSERT (gVariableInfo
->Name
!= NULL
);
145 StrCpy (gVariableInfo
->Name
, VariableName
);
146 gVariableInfo
->Volatile
= Volatile
;
148 gBS
->InstallConfigurationTable (&gEfiVariableInfoGuid
, gVariableInfo
);
152 for (Entry
= gVariableInfo
; Entry
!= NULL
; Entry
= Entry
->Next
) {
153 if (CompareGuid (VendorGuid
, &Entry
->VendorGuid
)) {
154 if (StrCmp (VariableName
, Entry
->Name
) == 0) {
162 Entry
->DeleteCount
++;
172 if (Entry
->Next
== NULL
) {
174 // If the entry is not in the table add it.
175 // Next iteration of the loop will fill in the data
177 Entry
->Next
= AllocateZeroPool (sizeof (VARIABLE_INFO_ENTRY
));
178 ASSERT (Entry
->Next
!= NULL
);
180 CopyGuid (&Entry
->Next
->VendorGuid
, VendorGuid
);
181 Entry
->Next
->Name
= AllocatePool (StrLen (VariableName
));
182 ASSERT (Entry
->Next
->Name
!= NULL
);
183 StrCpy (Entry
->Next
->Name
, VariableName
);
184 Entry
->Next
->Volatile
= Volatile
;
194 This code checks if variable header is valid or not.
196 @param Variable Pointer to the Variable Header.
198 @retval TRUE Variable header is valid.
199 @retval FALSE Variable header is not valid.
203 IsValidVariableHeader (
204 IN VARIABLE_HEADER
*Variable
207 if (Variable
== NULL
|| Variable
->StartId
!= VARIABLE_DATA
) {
217 This function writes data to the FWH at the correct LBA even if the LBAs
220 @param Global Pointer to VARAIBLE_GLOBAL structure
221 @param Volatile Point out the Variable is Volatile or Non-Volatile
222 @param SetByIndex TRUE if target pointer is given as index
223 FALSE if target pointer is absolute
224 @param Instance Instance of FV Block services
225 @param DataPtrIndex Pointer to the Data from the end of VARIABLE_STORE_HEADER
227 @param DataSize Size of data to be written
228 @param Buffer Pointer to the buffer from which data is written
230 @retval EFI_INVALID_PARAMETER Parameters not valid
231 @retval EFI_SUCCESS Variable store successfully updated
235 UpdateVariableStore (
236 IN VARIABLE_GLOBAL
*Global
,
238 IN BOOLEAN SetByIndex
,
240 IN UINTN DataPtrIndex
,
245 EFI_FV_BLOCK_MAP_ENTRY
*PtrBlockMapEntry
;
253 EFI_FIRMWARE_VOLUME_HEADER
*FwVolHeader
;
254 VARIABLE_STORE_HEADER
*VolatileBase
;
255 EFI_PHYSICAL_ADDRESS FvVolHdr
;
256 EFI_PHYSICAL_ADDRESS DataPtr
;
260 DataPtr
= DataPtrIndex
;
263 // Check if the Data is Volatile
266 EfiFvbGetPhysicalAddress (Instance
, &FvVolHdr
);
267 FwVolHeader
= (EFI_FIRMWARE_VOLUME_HEADER
*) ((UINTN
) FvVolHdr
);
269 // Data Pointer should point to the actual Address where data is to be
273 DataPtr
+= mVariableModuleGlobal
->VariableGlobal
.NonVolatileVariableBase
;
276 if ((DataPtr
+ DataSize
) >= ((EFI_PHYSICAL_ADDRESS
) (UINTN
) ((UINT8
*) FwVolHeader
+ FwVolHeader
->FvLength
))) {
277 return EFI_INVALID_PARAMETER
;
281 // Data Pointer should point to the actual Address where data is to be
284 VolatileBase
= (VARIABLE_STORE_HEADER
*) ((UINTN
) mVariableModuleGlobal
->VariableGlobal
.VolatileVariableBase
);
286 DataPtr
+= mVariableModuleGlobal
->VariableGlobal
.VolatileVariableBase
;
289 if ((DataPtr
+ DataSize
) >= ((UINTN
) ((UINT8
*) VolatileBase
+ VolatileBase
->Size
))) {
290 return EFI_INVALID_PARAMETER
;
294 // If Volatile Variable just do a simple mem copy.
296 CopyMem ((UINT8
*)(UINTN
)DataPtr
, Buffer
, DataSize
);
301 // If we are here we are dealing with Non-Volatile Variables
303 LinearOffset
= (UINTN
) FwVolHeader
;
304 CurrWritePtr
= (UINTN
) DataPtr
;
305 CurrWriteSize
= DataSize
;
309 if (CurrWritePtr
< LinearOffset
) {
310 return EFI_INVALID_PARAMETER
;
313 for (PtrBlockMapEntry
= FwVolHeader
->BlockMap
; PtrBlockMapEntry
->NumBlocks
!= 0; PtrBlockMapEntry
++) {
314 for (BlockIndex2
= 0; BlockIndex2
< PtrBlockMapEntry
->NumBlocks
; BlockIndex2
++) {
316 // Check to see if the Variable Writes are spanning through multiple
319 if ((CurrWritePtr
>= LinearOffset
) && (CurrWritePtr
< LinearOffset
+ PtrBlockMapEntry
->Length
)) {
320 if ((CurrWritePtr
+ CurrWriteSize
) <= (LinearOffset
+ PtrBlockMapEntry
->Length
)) {
321 Status
= EfiFvbWriteBlock (
324 (UINTN
) (CurrWritePtr
- LinearOffset
),
330 Size
= (UINT32
) (LinearOffset
+ PtrBlockMapEntry
->Length
- CurrWritePtr
);
331 Status
= EfiFvbWriteBlock (
334 (UINTN
) (CurrWritePtr
- LinearOffset
),
338 if (EFI_ERROR (Status
)) {
342 CurrWritePtr
= LinearOffset
+ PtrBlockMapEntry
->Length
;
343 CurrBuffer
= CurrBuffer
+ Size
;
344 CurrWriteSize
= CurrWriteSize
- Size
;
348 LinearOffset
+= PtrBlockMapEntry
->Length
;
359 This code gets the current status of Variable Store.
361 @param VarStoreHeader Pointer to the Variable Store Header.
363 @retval EfiRaw Variable store status is raw
364 @retval EfiValid Variable store status is valid
365 @retval EfiInvalid Variable store status is invalid
368 VARIABLE_STORE_STATUS
369 GetVariableStoreStatus (
370 IN VARIABLE_STORE_HEADER
*VarStoreHeader
373 if (VarStoreHeader
->Signature
== VARIABLE_STORE_SIGNATURE
&&
374 VarStoreHeader
->Format
== VARIABLE_STORE_FORMATTED
&&
375 VarStoreHeader
->State
== VARIABLE_STORE_HEALTHY
379 } else if (VarStoreHeader
->Signature
== 0xffffffff &&
380 VarStoreHeader
->Size
== 0xffffffff &&
381 VarStoreHeader
->Format
== 0xff &&
382 VarStoreHeader
->State
== 0xff
394 This code gets the size of name of variable.
396 @param Variable Pointer to the Variable Header
398 @return UINTN Size of variable in bytes
403 IN VARIABLE_HEADER
*Variable
406 if (Variable
->State
== (UINT8
) (-1) ||
407 Variable
->DataSize
== (UINT32
) (-1) ||
408 Variable
->NameSize
== (UINT32
) (-1) ||
409 Variable
->Attributes
== (UINT32
) (-1)) {
412 return (UINTN
) Variable
->NameSize
;
417 This code gets the size of variable data.
419 @param Variable Pointer to the Variable Header
421 @return Size of variable in bytes
426 IN VARIABLE_HEADER
*Variable
429 if (Variable
->State
== (UINT8
) (-1) ||
430 Variable
->DataSize
== (UINT32
) (-1) ||
431 Variable
->NameSize
== (UINT32
) (-1) ||
432 Variable
->Attributes
== (UINT32
) (-1)) {
435 return (UINTN
) Variable
->DataSize
;
440 This code gets the pointer to the variable name.
442 @param Variable Pointer to the Variable Header
444 @return Pointer to Variable Name which is Unicode encoding
449 IN VARIABLE_HEADER
*Variable
453 return (CHAR16
*) (Variable
+ 1);
458 This code gets the pointer to the variable data.
460 @param Variable Pointer to the Variable Header
462 @return Pointer to Variable Data
467 IN VARIABLE_HEADER
*Variable
473 // Be careful about pad size for alignment
475 Value
= (UINTN
) GetVariableNamePtr (Variable
);
476 Value
+= NameSizeOfVariable (Variable
);
477 Value
+= GET_PAD_SIZE (NameSizeOfVariable (Variable
));
479 return (UINT8
*) Value
;
485 This code gets the pointer to the next variable header.
487 @param Variable Pointer to the Variable Header
489 @return Pointer to next variable header
494 IN VARIABLE_HEADER
*Variable
499 if (!IsValidVariableHeader (Variable
)) {
503 Value
= (UINTN
) GetVariableDataPtr (Variable
);
504 Value
+= DataSizeOfVariable (Variable
);
505 Value
+= GET_PAD_SIZE (DataSizeOfVariable (Variable
));
508 // Be careful about pad size for alignment
510 return (VARIABLE_HEADER
*) HEADER_ALIGN (Value
);
515 Gets the pointer to the first variable header in given variable store area.
517 @param VarStoreHeader Pointer to the Variable Store Header.
519 @return Pointer to the first variable header
524 IN VARIABLE_STORE_HEADER
*VarStoreHeader
528 // The end of variable store
530 return (VARIABLE_HEADER
*) HEADER_ALIGN (VarStoreHeader
+ 1);
535 Gets the pointer to the end of the variable storage area.
537 This function gets pointer to the end of the variable storage
538 area, according to the input variable store header.
540 @param VarStoreHeader Pointer to the Variable Store Header
542 @return Pointer to the end of the variable storage area
547 IN VARIABLE_STORE_HEADER
*VarStoreHeader
551 // The end of variable store
553 return (VARIABLE_HEADER
*) HEADER_ALIGN ((UINTN
) VarStoreHeader
+ VarStoreHeader
->Size
);
559 Variable store garbage collection and reclaim operation.
561 @param VariableBase Base address of variable store
562 @param LastVariableOffset Offset of last variable
563 @param IsVolatile The variable store is volatile or not,
564 if it is non-volatile, need FTW
565 @param UpdatingVariable Pointer to updateing variable.
567 @return EFI_OUT_OF_RESOURCES
574 IN EFI_PHYSICAL_ADDRESS VariableBase
,
575 OUT UINTN
*LastVariableOffset
,
576 IN BOOLEAN IsVolatile
,
577 IN VARIABLE_HEADER
*UpdatingVariable
580 VARIABLE_HEADER
*Variable
;
581 VARIABLE_HEADER
*AddedVariable
;
582 VARIABLE_HEADER
*NextVariable
;
583 VARIABLE_HEADER
*NextAddedVariable
;
584 VARIABLE_STORE_HEADER
*VariableStoreHeader
;
586 UINTN MaximumBufferSize
;
588 UINTN VariableNameSize
;
589 UINTN UpdatingVariableNameSize
;
596 CHAR16
*VariableNamePtr
;
597 CHAR16
*UpdatingVariableNamePtr
;
599 VariableStoreHeader
= (VARIABLE_STORE_HEADER
*) ((UINTN
) VariableBase
);
602 // Start Pointers for the variable.
604 Variable
= GetStartPointer (VariableStoreHeader
);
605 MaximumBufferSize
= sizeof (VARIABLE_STORE_HEADER
);
607 while (IsValidVariableHeader (Variable
)) {
608 NextVariable
= GetNextVariablePtr (Variable
);
609 if (Variable
->State
== VAR_ADDED
||
610 Variable
->State
== (VAR_IN_DELETED_TRANSITION
& VAR_ADDED
)
612 VariableSize
= (UINTN
) NextVariable
- (UINTN
) Variable
;
613 MaximumBufferSize
+= VariableSize
;
616 Variable
= NextVariable
;
620 // Reserve the 1 Bytes with Oxff to identify the
621 // end of the variable buffer.
623 MaximumBufferSize
+= 1;
624 ValidBuffer
= AllocatePool (MaximumBufferSize
);
625 if (ValidBuffer
== NULL
) {
626 return EFI_OUT_OF_RESOURCES
;
629 SetMem (ValidBuffer
, MaximumBufferSize
, 0xff);
632 // Copy variable store header
634 CopyMem (ValidBuffer
, VariableStoreHeader
, sizeof (VARIABLE_STORE_HEADER
));
635 CurrPtr
= (UINT8
*) GetStartPointer ((VARIABLE_STORE_HEADER
*) ValidBuffer
);
638 // Reinstall all ADDED variables as long as they are not identical to Updating Variable
640 Variable
= GetStartPointer (VariableStoreHeader
);
641 while (IsValidVariableHeader (Variable
)) {
642 NextVariable
= GetNextVariablePtr (Variable
);
643 if (Variable
->State
== VAR_ADDED
) {
644 if (UpdatingVariable
!= NULL
) {
645 if (UpdatingVariable
== Variable
) {
646 Variable
= NextVariable
;
650 VariableNameSize
= NameSizeOfVariable(Variable
);
651 UpdatingVariableNameSize
= NameSizeOfVariable(UpdatingVariable
);
653 VariableNamePtr
= GetVariableNamePtr (Variable
);
654 UpdatingVariableNamePtr
= GetVariableNamePtr (UpdatingVariable
);
655 if (CompareGuid (&Variable
->VendorGuid
, &UpdatingVariable
->VendorGuid
) &&
656 VariableNameSize
== UpdatingVariableNameSize
&&
657 CompareMem (VariableNamePtr
, UpdatingVariableNamePtr
, VariableNameSize
) == 0 ) {
658 Variable
= NextVariable
;
662 VariableSize
= (UINTN
) NextVariable
- (UINTN
) Variable
;
663 CopyMem (CurrPtr
, (UINT8
*) Variable
, VariableSize
);
664 CurrPtr
+= VariableSize
;
666 Variable
= NextVariable
;
670 // Reinstall the variable being updated if it is not NULL
672 if (UpdatingVariable
!= NULL
) {
673 VariableSize
= (UINTN
)(GetNextVariablePtr (UpdatingVariable
)) - (UINTN
)UpdatingVariable
;
674 CopyMem (CurrPtr
, (UINT8
*) UpdatingVariable
, VariableSize
);
675 CurrPtr
+= VariableSize
;
679 // Reinstall all in delete transition variables
681 Variable
= GetStartPointer (VariableStoreHeader
);
682 while (IsValidVariableHeader (Variable
)) {
683 NextVariable
= GetNextVariablePtr (Variable
);
684 if (Variable
!= UpdatingVariable
&& Variable
->State
== (VAR_IN_DELETED_TRANSITION
& VAR_ADDED
)) {
687 // Buffer has cached all ADDED variable.
688 // Per IN_DELETED variable, we have to guarantee that
689 // no ADDED one in previous buffer.
693 AddedVariable
= GetStartPointer ((VARIABLE_STORE_HEADER
*) ValidBuffer
);
694 while (IsValidVariableHeader (AddedVariable
)) {
695 NextAddedVariable
= GetNextVariablePtr (AddedVariable
);
696 NameSize
= NameSizeOfVariable (AddedVariable
);
697 if (CompareGuid (&AddedVariable
->VendorGuid
, &Variable
->VendorGuid
) &&
698 NameSize
== NameSizeOfVariable (Variable
)
700 Point0
= (VOID
*) GetVariableNamePtr (AddedVariable
);
701 Point1
= (VOID
*) GetVariableNamePtr (Variable
);
702 if (CompareMem (Point0
, Point1
, NameSizeOfVariable (AddedVariable
)) == 0) {
707 AddedVariable
= NextAddedVariable
;
711 // Promote VAR_IN_DELETED_TRANSITION to VAR_ADDED
713 VariableSize
= (UINTN
) NextVariable
- (UINTN
) Variable
;
714 CopyMem (CurrPtr
, (UINT8
*) Variable
, VariableSize
);
715 ((VARIABLE_HEADER
*) CurrPtr
)->State
= VAR_ADDED
;
716 CurrPtr
+= VariableSize
;
720 Variable
= NextVariable
;
725 // If volatile variable store, just copy valid buffer
727 SetMem ((UINT8
*) (UINTN
) VariableBase
, VariableStoreHeader
->Size
, 0xff);
728 CopyMem ((UINT8
*) (UINTN
) VariableBase
, ValidBuffer
, (UINTN
) (CurrPtr
- (UINT8
*) ValidBuffer
));
729 Status
= EFI_SUCCESS
;
732 // If non-volatile variable store, perform FTW here.
734 Status
= FtwVariableSpace (
737 (UINTN
) (CurrPtr
- (UINT8
*) ValidBuffer
)
740 if (!EFI_ERROR (Status
)) {
741 *LastVariableOffset
= (UINTN
) (CurrPtr
- (UINT8
*) ValidBuffer
);
743 *LastVariableOffset
= 0;
746 FreePool (ValidBuffer
);
753 Update the Cache with Variable information. These are the same
754 arguments as the EFI Variable services.
756 @param[in] VariableName Name of variable
757 @param[in] VendorGuid Guid of variable
758 @param[in] Attributes Attribues of the variable
759 @param[in] DataSize Size of data. 0 means delete
760 @param[in] Data Variable data
764 UpdateVariableCache (
765 IN CHAR16
*VariableName
,
766 IN EFI_GUID
*VendorGuid
,
767 IN UINT32 Attributes
,
772 VARIABLE_CACHE_ENTRY
*Entry
;
775 if (EfiAtRuntime ()) {
776 // Don't use the cache at runtime
780 for (Index
= 0, Entry
= mVariableCache
; Index
< sizeof (mVariableCache
)/sizeof (VARIABLE_CACHE_ENTRY
); Index
++, Entry
++) {
781 if (CompareGuid (VendorGuid
, Entry
->Guid
)) {
782 if (StrCmp (VariableName
, Entry
->Name
) == 0) {
783 Entry
->Attributes
= Attributes
;
786 if (Entry
->DataSize
!= 0) {
787 FreePool (Entry
->Data
);
789 Entry
->DataSize
= DataSize
;
790 } else if (DataSize
== Entry
->DataSize
) {
791 CopyMem (Entry
->Data
, Data
, DataSize
);
793 Entry
->Data
= AllocatePool (DataSize
);
794 Entry
->DataSize
= DataSize
;
795 CopyMem (Entry
->Data
, Data
, DataSize
);
804 Search the cache to check if the variable is in it.
806 This function searches the variable cache. If the variable to find exists, return its data
809 @param VariableName A Null-terminated Unicode string that is the name of the vendor's
810 variable. Each VariableName is unique for each
812 @param VendorGuid A unique identifier for the vendor
813 @param Attributes Pointer to the attributes bitmask of the variable for output.
814 @param DataSize On input, size of the buffer of Data.
815 On output, size of the variable's data.
816 @param Data Pointer to the data buffer for output.
818 @retval EFI_SUCCESS VariableGuid & VariableName data was returned.
819 @retval EFI_NOT_FOUND No matching variable found in cache.
820 @retval EFI_BUFFER_TOO_SMALL *DataSize is smaller than size of the variable's data to return.
824 FindVariableInCache (
825 IN CHAR16
*VariableName
,
826 IN EFI_GUID
*VendorGuid
,
827 OUT UINT32
*Attributes OPTIONAL
,
828 IN OUT UINTN
*DataSize
,
832 VARIABLE_CACHE_ENTRY
*Entry
;
835 if (EfiAtRuntime ()) {
836 // Don't use the cache at runtime
837 return EFI_NOT_FOUND
;
840 for (Index
= 0, Entry
= mVariableCache
; Index
< sizeof (mVariableCache
)/sizeof (VARIABLE_CACHE_ENTRY
); Index
++, Entry
++) {
841 if (CompareGuid (VendorGuid
, Entry
->Guid
)) {
842 if (StrCmp (VariableName
, Entry
->Name
) == 0) {
843 if (Entry
->DataSize
== 0) {
844 // Variable was deleted so return not found
845 return EFI_NOT_FOUND
;
846 } else if (Entry
->DataSize
> *DataSize
) {
847 // If the buffer is too small return correct size
848 *DataSize
= Entry
->DataSize
;
849 return EFI_BUFFER_TOO_SMALL
;
851 *DataSize
= Entry
->DataSize
;
853 CopyMem (Data
, Entry
->Data
, Entry
->DataSize
);
854 if (Attributes
!= NULL
) {
855 *Attributes
= Entry
->Attributes
;
863 return EFI_NOT_FOUND
;
867 Finds variable in storage blocks of volatile and non-volatile storage areas.
869 This code finds variable in storage blocks of volatile and non-volatile storage areas.
870 If VariableName is an empty string, then we just return the first
871 qualified variable without comparing VariableName and VendorGuid.
872 Otherwise, VariableName and VendorGuid are compared.
874 @param VariableName Name of the variable to be found
875 @param VendorGuid Vendor GUID to be found.
876 @param PtrTrack VARIABLE_POINTER_TRACK structure for output,
877 including the range searched and the target position.
878 @param Global Pointer to VARIABLE_GLOBAL structure, including
879 base of volatile variable storage area, base of
880 NV variable storage area, and a lock.
882 @retval EFI_INVALID_PARAMETER If VariableName is not an empty string, while
884 @retval EFI_SUCCESS Variable successfully found
885 @retval EFI_INVALID_PARAMETER Variable not found
890 IN CHAR16
*VariableName
,
891 IN EFI_GUID
*VendorGuid
,
892 OUT VARIABLE_POINTER_TRACK
*PtrTrack
,
893 IN VARIABLE_GLOBAL
*Global
896 VARIABLE_HEADER
*Variable
[2];
897 VARIABLE_HEADER
*InDeletedVariable
;
898 VARIABLE_STORE_HEADER
*VariableStoreHeader
[2];
899 UINTN InDeletedStorageIndex
;
904 // 0: Volatile, 1: Non-Volatile
905 // The index and attributes mapping must be kept in this order as RuntimeServiceGetNextVariableName
906 // make use of this mapping to implement search algorithme.
908 VariableStoreHeader
[0] = (VARIABLE_STORE_HEADER
*) ((UINTN
) mVariableModuleGlobal
->VariableGlobal
.VolatileVariableBase
);
909 VariableStoreHeader
[1] = (VARIABLE_STORE_HEADER
*) ((UINTN
) mVariableModuleGlobal
->VariableGlobal
.NonVolatileVariableBase
);
912 // Start Pointers for the variable.
913 // Actual Data Pointer where data can be written.
915 Variable
[0] = GetStartPointer (VariableStoreHeader
[0]);
916 Variable
[1] = GetStartPointer (VariableStoreHeader
[1]);
918 if (VariableName
[0] != 0 && VendorGuid
== NULL
) {
919 return EFI_INVALID_PARAMETER
;
923 // Find the variable by walk through volatile and then non-volatile variable store
925 InDeletedVariable
= NULL
;
926 InDeletedStorageIndex
= 0;
927 for (Index
= 0; Index
< 2; Index
++) {
928 while (IsValidVariableHeader (Variable
[Index
]) && (Variable
[Index
] <= GetEndPointer (VariableStoreHeader
[Index
]))) {
929 if (Variable
[Index
]->State
== VAR_ADDED
||
930 Variable
[Index
]->State
== (VAR_IN_DELETED_TRANSITION
& VAR_ADDED
)
932 if (!EfiAtRuntime () || (Variable
[Index
]->Attributes
& EFI_VARIABLE_RUNTIME_ACCESS
)) {
933 if (VariableName
[0] == 0) {
934 if (Variable
[Index
]->State
== (VAR_IN_DELETED_TRANSITION
& VAR_ADDED
)) {
935 InDeletedVariable
= Variable
[Index
];
936 InDeletedStorageIndex
= Index
;
938 PtrTrack
->StartPtr
= GetStartPointer (VariableStoreHeader
[Index
]);
939 PtrTrack
->EndPtr
= GetEndPointer (VariableStoreHeader
[Index
]);
940 PtrTrack
->CurrPtr
= Variable
[Index
];
941 PtrTrack
->Volatile
= (BOOLEAN
)(Index
== 0);
946 if (CompareGuid (VendorGuid
, &Variable
[Index
]->VendorGuid
)) {
947 Point
= (VOID
*) GetVariableNamePtr (Variable
[Index
]);
949 ASSERT (NameSizeOfVariable (Variable
[Index
]) != 0);
950 if (!CompareMem (VariableName
, Point
, NameSizeOfVariable (Variable
[Index
]))) {
951 if (Variable
[Index
]->State
== (VAR_IN_DELETED_TRANSITION
& VAR_ADDED
)) {
952 InDeletedVariable
= Variable
[Index
];
953 InDeletedStorageIndex
= Index
;
955 PtrTrack
->StartPtr
= GetStartPointer (VariableStoreHeader
[Index
]);
956 PtrTrack
->EndPtr
= GetEndPointer (VariableStoreHeader
[Index
]);
957 PtrTrack
->CurrPtr
= Variable
[Index
];
958 PtrTrack
->Volatile
= (BOOLEAN
)(Index
== 0);
968 Variable
[Index
] = GetNextVariablePtr (Variable
[Index
]);
970 if (InDeletedVariable
!= NULL
) {
971 PtrTrack
->StartPtr
= GetStartPointer (VariableStoreHeader
[InDeletedStorageIndex
]);
972 PtrTrack
->EndPtr
= GetEndPointer (VariableStoreHeader
[InDeletedStorageIndex
]);
973 PtrTrack
->CurrPtr
= InDeletedVariable
;
974 PtrTrack
->Volatile
= (BOOLEAN
)(InDeletedStorageIndex
== 0);
978 PtrTrack
->CurrPtr
= NULL
;
979 return EFI_NOT_FOUND
;
985 This code finds variable in storage blocks (Volatile or Non-Volatile).
987 @param VariableName Name of Variable to be found.
988 @param VendorGuid Variable vendor GUID.
989 @param Attributes Attribute value of the variable found.
990 @param DataSize Size of Data found. If size is less than the
991 data, this value contains the required size.
992 @param Data Data pointer.
994 @return EFI_INVALID_PARAMETER Invalid parameter
995 @return EFI_SUCCESS Find the specified variable
996 @return EFI_NOT_FOUND Not found
997 @return EFI_BUFFER_TO_SMALL DataSize is too small for the result
1002 RuntimeServiceGetVariable (
1003 IN CHAR16
*VariableName
,
1004 IN EFI_GUID
*VendorGuid
,
1005 OUT UINT32
*Attributes OPTIONAL
,
1006 IN OUT UINTN
*DataSize
,
1011 VARIABLE_POINTER_TRACK Variable
;
1014 if (VariableName
== NULL
|| VendorGuid
== NULL
|| DataSize
== NULL
) {
1015 return EFI_INVALID_PARAMETER
;
1018 AcquireLockOnlyAtBootTime(&mVariableModuleGlobal
->VariableGlobal
.VariableServicesLock
);
1021 // Find existing variable
1023 Status
= FindVariableInCache (VariableName
, VendorGuid
, Attributes
, DataSize
, Data
);
1024 if ((Status
== EFI_BUFFER_TOO_SMALL
) || (Status
== EFI_SUCCESS
)){
1026 UpdateVariableInfo (VariableName
, VendorGuid
, FALSE
, TRUE
, FALSE
, FALSE
, TRUE
);
1030 Status
= FindVariable (VariableName
, VendorGuid
, &Variable
, &mVariableModuleGlobal
->VariableGlobal
);
1031 if (Variable
.CurrPtr
== NULL
|| EFI_ERROR (Status
)) {
1038 VarDataSize
= DataSizeOfVariable (Variable
.CurrPtr
);
1039 ASSERT (VarDataSize
!= 0);
1041 if (*DataSize
>= VarDataSize
) {
1043 Status
= EFI_INVALID_PARAMETER
;
1047 CopyMem (Data
, GetVariableDataPtr (Variable
.CurrPtr
), VarDataSize
);
1048 if (Attributes
!= NULL
) {
1049 *Attributes
= Variable
.CurrPtr
->Attributes
;
1052 *DataSize
= VarDataSize
;
1053 UpdateVariableInfo (VariableName
, VendorGuid
, Variable
.Volatile
, TRUE
, FALSE
, FALSE
, FALSE
);
1054 UpdateVariableCache (VariableName
, VendorGuid
, Variable
.CurrPtr
->Attributes
, VarDataSize
, Data
);
1056 Status
= EFI_SUCCESS
;
1059 *DataSize
= VarDataSize
;
1060 Status
= EFI_BUFFER_TOO_SMALL
;
1065 ReleaseLockOnlyAtBootTime (&mVariableModuleGlobal
->VariableGlobal
.VariableServicesLock
);
1073 This code Finds the Next available variable.
1075 @param VariableNameSize Size of the variable name
1076 @param VariableName Pointer to variable name
1077 @param VendorGuid Variable Vendor Guid
1079 @return EFI_INVALID_PARAMETER Invalid parameter
1080 @return EFI_SUCCESS Find the specified variable
1081 @return EFI_NOT_FOUND Not found
1082 @return EFI_BUFFER_TO_SMALL DataSize is too small for the result
1087 RuntimeServiceGetNextVariableName (
1088 IN OUT UINTN
*VariableNameSize
,
1089 IN OUT CHAR16
*VariableName
,
1090 IN OUT EFI_GUID
*VendorGuid
1093 VARIABLE_POINTER_TRACK Variable
;
1097 if (VariableNameSize
== NULL
|| VariableName
== NULL
|| VendorGuid
== NULL
) {
1098 return EFI_INVALID_PARAMETER
;
1101 AcquireLockOnlyAtBootTime(&mVariableModuleGlobal
->VariableGlobal
.VariableServicesLock
);
1103 Status
= FindVariable (VariableName
, VendorGuid
, &Variable
, &mVariableModuleGlobal
->VariableGlobal
);
1104 if (Variable
.CurrPtr
== NULL
|| EFI_ERROR (Status
)) {
1108 if (VariableName
[0] != 0) {
1110 // If variable name is not NULL, get next variable
1112 Variable
.CurrPtr
= GetNextVariablePtr (Variable
.CurrPtr
);
1117 // If both volatile and non-volatile variable store are parsed,
1120 if (Variable
.CurrPtr
>= Variable
.EndPtr
|| Variable
.CurrPtr
== NULL
) {
1121 Variable
.Volatile
= (BOOLEAN
) (Variable
.Volatile
^ ((BOOLEAN
) 0x1));
1122 if (!Variable
.Volatile
) {
1123 Variable
.StartPtr
= GetStartPointer ((VARIABLE_STORE_HEADER
*) (UINTN
) mVariableModuleGlobal
->VariableGlobal
.NonVolatileVariableBase
);
1124 Variable
.EndPtr
= GetEndPointer ((VARIABLE_STORE_HEADER
*) ((UINTN
) mVariableModuleGlobal
->VariableGlobal
.NonVolatileVariableBase
));
1126 Status
= EFI_NOT_FOUND
;
1130 Variable
.CurrPtr
= Variable
.StartPtr
;
1131 if (!IsValidVariableHeader (Variable
.CurrPtr
)) {
1136 // Variable is found
1138 if (IsValidVariableHeader (Variable
.CurrPtr
) && Variable
.CurrPtr
->State
== VAR_ADDED
) {
1139 if (!(EfiAtRuntime () && !(Variable
.CurrPtr
->Attributes
& EFI_VARIABLE_RUNTIME_ACCESS
))) {
1140 VarNameSize
= NameSizeOfVariable (Variable
.CurrPtr
);
1141 ASSERT (VarNameSize
!= 0);
1143 if (VarNameSize
<= *VariableNameSize
) {
1146 GetVariableNamePtr (Variable
.CurrPtr
),
1151 &Variable
.CurrPtr
->VendorGuid
,
1154 Status
= EFI_SUCCESS
;
1156 Status
= EFI_BUFFER_TOO_SMALL
;
1159 *VariableNameSize
= VarNameSize
;
1164 Variable
.CurrPtr
= GetNextVariablePtr (Variable
.CurrPtr
);
1168 ReleaseLockOnlyAtBootTime (&mVariableModuleGlobal
->VariableGlobal
.VariableServicesLock
);
1174 This code sets variable in storage blocks (Volatile or Non-Volatile).
1176 @param VariableName Name of Variable to be found
1177 @param VendorGuid Variable vendor GUID
1178 @param Attributes Attribute value of the variable found
1179 @param DataSize Size of Data found. If size is less than the
1180 data, this value contains the required size.
1181 @param Data Data pointer
1183 @return EFI_INVALID_PARAMETER Invalid parameter
1184 @return EFI_SUCCESS Set successfully
1185 @return EFI_OUT_OF_RESOURCES Resource not enough to set variable
1186 @return EFI_NOT_FOUND Not found
1187 @return EFI_WRITE_PROTECTED Variable is read-only
1192 RuntimeServiceSetVariable (
1193 IN CHAR16
*VariableName
,
1194 IN EFI_GUID
*VendorGuid
,
1195 IN UINT32 Attributes
,
1200 VARIABLE_POINTER_TRACK Variable
;
1202 VARIABLE_HEADER
*NextVariable
;
1204 UINTN VarNameOffset
;
1205 UINTN VarDataOffset
;
1209 UINTN
*VolatileOffset
;
1210 UINTN
*NonVolatileOffset
;
1213 EFI_PHYSICAL_ADDRESS Point
;
1216 // Check input parameters
1218 if (VariableName
== NULL
|| VariableName
[0] == 0 || VendorGuid
== NULL
) {
1219 return EFI_INVALID_PARAMETER
;
1222 // Make sure if runtime bit is set, boot service bit is set also
1224 if ((Attributes
& (EFI_VARIABLE_RUNTIME_ACCESS
| EFI_VARIABLE_BOOTSERVICE_ACCESS
)) == EFI_VARIABLE_RUNTIME_ACCESS
) {
1225 return EFI_INVALID_PARAMETER
;
1229 // The size of the VariableName, including the Unicode Null in bytes plus
1230 // the DataSize is limited to maximum size of FixedPcdGet32(PcdMaxHardwareErrorVariableSize)
1231 // bytes for HwErrRec, and FixedPcdGet32(PcdMaxVariableSize) bytes for the others.
1233 if ((Attributes
& EFI_VARIABLE_HARDWARE_ERROR_RECORD
) == EFI_VARIABLE_HARDWARE_ERROR_RECORD
) {
1234 if ((DataSize
> FixedPcdGet32(PcdMaxHardwareErrorVariableSize
)) ||
1235 (sizeof (VARIABLE_HEADER
) + StrSize (VariableName
) + DataSize
> FixedPcdGet32(PcdMaxHardwareErrorVariableSize
))) {
1236 return EFI_INVALID_PARAMETER
;
1240 // The size of the VariableName, including the Unicode Null in bytes plus
1241 // the DataSize is limited to maximum size of FixedPcdGet32(PcdMaxVariableSize) bytes.
1243 if ((DataSize
> FixedPcdGet32(PcdMaxVariableSize
)) ||
1244 (sizeof (VARIABLE_HEADER
) + StrSize (VariableName
) + DataSize
> FixedPcdGet32(PcdMaxVariableSize
))) {
1245 return EFI_INVALID_PARAMETER
;
1249 AcquireLockOnlyAtBootTime(&mVariableModuleGlobal
->VariableGlobal
.VariableServicesLock
);
1252 Instance
= mVariableModuleGlobal
->FvbInstance
;
1253 VolatileOffset
= &mVariableModuleGlobal
->VolatileLastVariableOffset
;
1256 // Consider reentrant in MCA/INIT/NMI. It needs be reupdated;
1258 if (1 < InterlockedIncrement (&mVariableModuleGlobal
->VariableGlobal
.ReentrantState
)) {
1259 Point
= mVariableModuleGlobal
->VariableGlobal
.NonVolatileVariableBase
;;
1261 // Parse non-volatile variable data and get last variable offset
1263 NextVariable
= GetStartPointer ((VARIABLE_STORE_HEADER
*) (UINTN
) Point
);
1264 while (IsValidVariableHeader (NextVariable
)) {
1265 NextVariable
= GetNextVariablePtr (NextVariable
);
1267 mVariableModuleGlobal
->NonVolatileLastVariableOffset
= (UINTN
) NextVariable
- (UINTN
) Point
;
1270 NonVolatileOffset
= &mVariableModuleGlobal
->NonVolatileLastVariableOffset
;
1274 // Check whether the input variable is already existed
1277 Status
= FindVariable (VariableName
, VendorGuid
, &Variable
, &mVariableModuleGlobal
->VariableGlobal
);
1278 if (Status
== EFI_SUCCESS
&& Variable
.CurrPtr
!= NULL
) {
1280 // Update/Delete existing variable
1282 Volatile
= Variable
.Volatile
;
1284 if (EfiAtRuntime ()) {
1286 // If EfiAtRuntime and the variable is Volatile and Runtime Access,
1287 // the volatile is ReadOnly, and SetVariable should be aborted and
1288 // return EFI_WRITE_PROTECTED.
1290 if (Variable
.Volatile
) {
1291 Status
= EFI_WRITE_PROTECTED
;
1295 // Only variable have NV attribute can be updated/deleted in Runtime
1297 if (!(Variable
.CurrPtr
->Attributes
& EFI_VARIABLE_NON_VOLATILE
)) {
1298 Status
= EFI_INVALID_PARAMETER
;
1303 // Setting a data variable with no access, or zero DataSize attributes
1304 // specified causes it to be deleted.
1306 if (DataSize
== 0 || (Attributes
& (EFI_VARIABLE_RUNTIME_ACCESS
| EFI_VARIABLE_BOOTSERVICE_ACCESS
)) == 0) {
1307 State
= Variable
.CurrPtr
->State
;
1308 State
&= VAR_DELETED
;
1310 Status
= UpdateVariableStore (
1311 &mVariableModuleGlobal
->VariableGlobal
,
1315 (UINTN
) &Variable
.CurrPtr
->State
,
1319 if (!EFI_ERROR (Status
)) {
1320 UpdateVariableInfo (VariableName
, VendorGuid
, Volatile
, FALSE
, FALSE
, TRUE
, FALSE
);
1321 UpdateVariableCache (VariableName
, VendorGuid
, Attributes
, DataSize
, Data
);
1326 // If the variable is marked valid and the same data has been passed in
1327 // then return to the caller immediately.
1329 if (DataSizeOfVariable (Variable
.CurrPtr
) == DataSize
&&
1330 (CompareMem (Data
, GetVariableDataPtr (Variable
.CurrPtr
), DataSize
) == 0)) {
1332 UpdateVariableInfo (VariableName
, VendorGuid
, Volatile
, FALSE
, TRUE
, FALSE
, FALSE
);
1333 Status
= EFI_SUCCESS
;
1335 } else if ((Variable
.CurrPtr
->State
== VAR_ADDED
) ||
1336 (Variable
.CurrPtr
->State
== (VAR_ADDED
& VAR_IN_DELETED_TRANSITION
))) {
1339 // Mark the old variable as in delete transition
1341 State
= Variable
.CurrPtr
->State
;
1342 State
&= VAR_IN_DELETED_TRANSITION
;
1344 Status
= UpdateVariableStore (
1345 &mVariableModuleGlobal
->VariableGlobal
,
1349 (UINTN
) &Variable
.CurrPtr
->State
,
1353 if (EFI_ERROR (Status
)) {
1357 } else if (Status
== EFI_NOT_FOUND
) {
1359 // Create a new variable
1363 // Make sure we are trying to create a new variable.
1364 // Setting a data variable with no access, or zero DataSize attributes means to delete it.
1366 if (DataSize
== 0 || (Attributes
& (EFI_VARIABLE_RUNTIME_ACCESS
| EFI_VARIABLE_BOOTSERVICE_ACCESS
)) == 0) {
1367 Status
= EFI_NOT_FOUND
;
1372 // Only variable have NV|RT attribute can be created in Runtime
1374 if (EfiAtRuntime () &&
1375 (((Attributes
& EFI_VARIABLE_RUNTIME_ACCESS
) == 0) || ((Attributes
& EFI_VARIABLE_NON_VOLATILE
) == 0))) {
1376 Status
= EFI_INVALID_PARAMETER
;
1381 // Status should be EFI_INVALID_PARAMETER here according to return status of FindVariable().
1383 ASSERT (Status
== EFI_INVALID_PARAMETER
);
1388 // Function part - create a new variable and copy the data.
1389 // Both update a variable and create a variable will come here.
1391 // Tricky part: Use scratch data area at the end of volatile variable store
1392 // as a temporary storage.
1394 NextVariable
= GetEndPointer ((VARIABLE_STORE_HEADER
*) ((UINTN
) mVariableModuleGlobal
->VariableGlobal
.VolatileVariableBase
));
1396 SetMem (NextVariable
, FixedPcdGet32(PcdMaxVariableSize
), 0xff);
1398 NextVariable
->StartId
= VARIABLE_DATA
;
1399 NextVariable
->Attributes
= Attributes
;
1401 // NextVariable->State = VAR_ADDED;
1403 NextVariable
->Reserved
= 0;
1404 VarNameOffset
= sizeof (VARIABLE_HEADER
);
1405 VarNameSize
= StrSize (VariableName
);
1407 (UINT8
*) ((UINTN
) NextVariable
+ VarNameOffset
),
1411 VarDataOffset
= VarNameOffset
+ VarNameSize
+ GET_PAD_SIZE (VarNameSize
);
1413 (UINT8
*) ((UINTN
) NextVariable
+ VarDataOffset
),
1417 CopyMem (&NextVariable
->VendorGuid
, VendorGuid
, sizeof (EFI_GUID
));
1419 // There will be pad bytes after Data, the NextVariable->NameSize and
1420 // NextVariable->DataSize should not include pad size so that variable
1421 // service can get actual size in GetVariable
1423 NextVariable
->NameSize
= (UINT32
)VarNameSize
;
1424 NextVariable
->DataSize
= (UINT32
)DataSize
;
1427 // The actual size of the variable that stores in storage should
1428 // include pad size.
1430 VarSize
= VarDataOffset
+ DataSize
+ GET_PAD_SIZE (DataSize
);
1431 if ((Attributes
& EFI_VARIABLE_NON_VOLATILE
) != 0) {
1433 // Create a nonvolatile variable
1437 if ((UINT32
) (VarSize
+*NonVolatileOffset
) >
1438 ((VARIABLE_STORE_HEADER
*) ((UINTN
) (mVariableModuleGlobal
->VariableGlobal
.NonVolatileVariableBase
)))->Size
1440 if (EfiAtRuntime ()) {
1441 Status
= EFI_OUT_OF_RESOURCES
;
1445 // Perform garbage collection & reclaim operation
1447 Status
= Reclaim (mVariableModuleGlobal
->VariableGlobal
.NonVolatileVariableBase
, NonVolatileOffset
, FALSE
, Variable
.CurrPtr
);
1448 if (EFI_ERROR (Status
)) {
1452 // If still no enough space, return out of resources
1454 if ((UINT32
) (VarSize
+*NonVolatileOffset
) >
1455 ((VARIABLE_STORE_HEADER
*) ((UINTN
) (mVariableModuleGlobal
->VariableGlobal
.NonVolatileVariableBase
)))->Size
1457 Status
= EFI_OUT_OF_RESOURCES
;
1465 // 1. Write variable header
1466 // 2. Set variable state to header valid
1467 // 3. Write variable data
1468 // 4. Set variable state to valid
1473 Status
= UpdateVariableStore (
1474 &mVariableModuleGlobal
->VariableGlobal
,
1479 sizeof (VARIABLE_HEADER
),
1480 (UINT8
*) NextVariable
1483 if (EFI_ERROR (Status
)) {
1490 NextVariable
->State
= VAR_HEADER_VALID_ONLY
;
1491 Status
= UpdateVariableStore (
1492 &mVariableModuleGlobal
->VariableGlobal
,
1497 sizeof (VARIABLE_HEADER
),
1498 (UINT8
*) NextVariable
1501 if (EFI_ERROR (Status
)) {
1507 Status
= UpdateVariableStore (
1508 &mVariableModuleGlobal
->VariableGlobal
,
1512 *NonVolatileOffset
+ sizeof (VARIABLE_HEADER
),
1513 (UINT32
) VarSize
- sizeof (VARIABLE_HEADER
),
1514 (UINT8
*) NextVariable
+ sizeof (VARIABLE_HEADER
)
1517 if (EFI_ERROR (Status
)) {
1523 NextVariable
->State
= VAR_ADDED
;
1524 Status
= UpdateVariableStore (
1525 &mVariableModuleGlobal
->VariableGlobal
,
1530 sizeof (VARIABLE_HEADER
),
1531 (UINT8
*) NextVariable
1534 if (EFI_ERROR (Status
)) {
1538 *NonVolatileOffset
= HEADER_ALIGN (*NonVolatileOffset
+ VarSize
);
1542 // Create a volatile variable
1546 if ((UINT32
) (VarSize
+*VolatileOffset
) >
1547 ((VARIABLE_STORE_HEADER
*) ((UINTN
) (mVariableModuleGlobal
->VariableGlobal
.VolatileVariableBase
)))->Size
) {
1549 // Perform garbage collection & reclaim operation
1551 Status
= Reclaim (mVariableModuleGlobal
->VariableGlobal
.VolatileVariableBase
, VolatileOffset
, TRUE
, Variable
.CurrPtr
);
1552 if (EFI_ERROR (Status
)) {
1556 // If still no enough space, return out of resources
1558 if ((UINT32
) (VarSize
+*VolatileOffset
) >
1559 ((VARIABLE_STORE_HEADER
*) ((UINTN
) (mVariableModuleGlobal
->VariableGlobal
.VolatileVariableBase
)))->Size
1561 Status
= EFI_OUT_OF_RESOURCES
;
1568 NextVariable
->State
= VAR_ADDED
;
1569 Status
= UpdateVariableStore (
1570 &mVariableModuleGlobal
->VariableGlobal
,
1576 (UINT8
*) NextVariable
1579 if (EFI_ERROR (Status
)) {
1583 *VolatileOffset
= HEADER_ALIGN (*VolatileOffset
+ VarSize
);
1586 // Mark the old variable as deleted
1588 if (!Reclaimed
&& !EFI_ERROR (Status
) && Variable
.CurrPtr
!= NULL
) {
1589 State
= Variable
.CurrPtr
->State
;
1590 State
&= VAR_DELETED
;
1592 Status
= UpdateVariableStore (
1593 &mVariableModuleGlobal
->VariableGlobal
,
1597 (UINTN
) &Variable
.CurrPtr
->State
,
1602 if (!EFI_ERROR (Status
)) {
1603 UpdateVariableInfo (VariableName
, VendorGuid
, Volatile
, FALSE
, TRUE
, FALSE
, FALSE
);
1604 UpdateVariableCache (VariableName
, VendorGuid
, Attributes
, DataSize
, Data
);
1609 Status
= EFI_SUCCESS
;
1610 UpdateVariableInfo (VariableName
, VendorGuid
, Volatile
, FALSE
, TRUE
, FALSE
, FALSE
);
1611 UpdateVariableCache (VariableName
, VendorGuid
, Attributes
, DataSize
, Data
);
1614 InterlockedDecrement (&mVariableModuleGlobal
->VariableGlobal
.ReentrantState
);
1615 ReleaseLockOnlyAtBootTime (&mVariableModuleGlobal
->VariableGlobal
.VariableServicesLock
);
1622 This code returns information about the EFI variables.
1624 @param Attributes Attributes bitmask to specify the type of variables
1625 on which to return information.
1626 @param MaximumVariableStorageSize Pointer to the maximum size of the storage space available
1627 for the EFI variables associated with the attributes specified.
1628 @param RemainingVariableStorageSize Pointer to the remaining size of the storage space available
1629 for EFI variables associated with the attributes specified.
1630 @param MaximumVariableSize Pointer to the maximum size of an individual EFI variables
1631 associated with the attributes specified.
1633 @return EFI_INVALID_PARAMETER An invalid combination of attribute bits was supplied.
1634 @return EFI_SUCCESS Query successfully.
1635 @return EFI_UNSUPPORTED The attribute is not supported on this platform.
1640 RuntimeServiceQueryVariableInfo (
1641 IN UINT32 Attributes
,
1642 OUT UINT64
*MaximumVariableStorageSize
,
1643 OUT UINT64
*RemainingVariableStorageSize
,
1644 OUT UINT64
*MaximumVariableSize
1647 VARIABLE_HEADER
*Variable
;
1648 VARIABLE_HEADER
*NextVariable
;
1649 UINT64 VariableSize
;
1650 VARIABLE_STORE_HEADER
*VariableStoreHeader
;
1652 if(MaximumVariableStorageSize
== NULL
|| RemainingVariableStorageSize
== NULL
|| MaximumVariableSize
== NULL
|| Attributes
== 0) {
1653 return EFI_INVALID_PARAMETER
;
1656 if((Attributes
& (EFI_VARIABLE_NON_VOLATILE
| EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_RUNTIME_ACCESS
| EFI_VARIABLE_HARDWARE_ERROR_RECORD
)) == 0) {
1658 // Make sure the Attributes combination is supported by the platform.
1660 return EFI_UNSUPPORTED
;
1661 } else if ((Attributes
& (EFI_VARIABLE_RUNTIME_ACCESS
| EFI_VARIABLE_BOOTSERVICE_ACCESS
)) == EFI_VARIABLE_RUNTIME_ACCESS
) {
1663 // Make sure if runtime bit is set, boot service bit is set also.
1665 return EFI_INVALID_PARAMETER
;
1666 } else if (EfiAtRuntime () && ((Attributes
& EFI_VARIABLE_RUNTIME_ACCESS
) == 0)) {
1668 // Make sure RT Attribute is set if we are in Runtime phase.
1670 return EFI_INVALID_PARAMETER
;
1673 AcquireLockOnlyAtBootTime(&mVariableModuleGlobal
->VariableGlobal
.VariableServicesLock
);
1675 if((Attributes
& EFI_VARIABLE_NON_VOLATILE
) == 0) {
1677 // Query is Volatile related.
1679 VariableStoreHeader
= (VARIABLE_STORE_HEADER
*) ((UINTN
) mVariableModuleGlobal
->VariableGlobal
.VolatileVariableBase
);
1682 // Query is Non-Volatile related.
1684 VariableStoreHeader
= (VARIABLE_STORE_HEADER
*) ((UINTN
) mVariableModuleGlobal
->VariableGlobal
.NonVolatileVariableBase
);
1688 // Now let's fill *MaximumVariableStorageSize *RemainingVariableStorageSize
1689 // with the storage size (excluding the storage header size).
1691 *MaximumVariableStorageSize
= VariableStoreHeader
->Size
- sizeof (VARIABLE_STORE_HEADER
);
1692 *RemainingVariableStorageSize
= VariableStoreHeader
->Size
- sizeof (VARIABLE_STORE_HEADER
);
1695 // Let *MaximumVariableSize be FixedPcdGet32(PcdMaxVariableSize) with the exception of the variable header size.
1697 *MaximumVariableSize
= FixedPcdGet32(PcdMaxVariableSize
) - sizeof (VARIABLE_HEADER
);
1700 // Harware error record variable needs larger size.
1702 if ((Attributes
& EFI_VARIABLE_HARDWARE_ERROR_RECORD
) == EFI_VARIABLE_HARDWARE_ERROR_RECORD
) {
1703 *MaximumVariableSize
= FixedPcdGet32(PcdMaxHardwareErrorVariableSize
) - sizeof (VARIABLE_HEADER
);
1707 // Point to the starting address of the variables.
1709 Variable
= GetStartPointer (VariableStoreHeader
);
1712 // Now walk through the related variable store.
1714 while (IsValidVariableHeader (Variable
) && (Variable
< GetEndPointer (VariableStoreHeader
))) {
1715 NextVariable
= GetNextVariablePtr (Variable
);
1716 VariableSize
= (UINT64
) (UINTN
) NextVariable
- (UINT64
) (UINTN
) Variable
;
1718 if (EfiAtRuntime ()) {
1720 // we don't take the state of the variables in mind
1721 // when calculating RemainingVariableStorageSize,
1722 // since the space occupied by variables not marked with
1723 // VAR_ADDED is not allowed to be reclaimed in Runtime.
1725 *RemainingVariableStorageSize
-= VariableSize
;
1728 // Only care about Variables with State VAR_ADDED,because
1729 // the space not marked as VAR_ADDED is reclaimable now.
1731 if (Variable
->State
== VAR_ADDED
) {
1732 *RemainingVariableStorageSize
-= VariableSize
;
1737 // Go to the next one
1739 Variable
= NextVariable
;
1742 if (*RemainingVariableStorageSize
< sizeof (VARIABLE_HEADER
)) {
1743 *MaximumVariableSize
= 0;
1744 } else if ((*RemainingVariableStorageSize
- sizeof (VARIABLE_HEADER
)) < *MaximumVariableSize
) {
1745 *MaximumVariableSize
= *RemainingVariableStorageSize
- sizeof (VARIABLE_HEADER
);
1748 ReleaseLockOnlyAtBootTime (&mVariableModuleGlobal
->VariableGlobal
.VariableServicesLock
);
1754 Notification function of EVT_GROUP_READY_TO_BOOT event group.
1756 This is a notification function registered on EVT_GROUP_READY_TO_BOOT event group.
1757 When the Boot Manager is about to load and execute a boot option, it reclaims variable
1758 storage if free size is below the threshold.
1760 @param Event Event whose notification function is being invoked
1761 @param Context Pointer to the notification function's context
1774 VarSize
= ((VARIABLE_STORE_HEADER
*) ((UINTN
) mVariableModuleGlobal
->VariableGlobal
.NonVolatileVariableBase
))->Size
;
1775 Status
= EFI_SUCCESS
;
1778 // Check if the free area is blow a threshold
1780 if ((VarSize
- mVariableModuleGlobal
->NonVolatileLastVariableOffset
) < VARIABLE_RECLAIM_THRESHOLD
) {
1782 mVariableModuleGlobal
->VariableGlobal
.NonVolatileVariableBase
,
1783 &mVariableModuleGlobal
->NonVolatileLastVariableOffset
,
1787 ASSERT_EFI_ERROR (Status
);
1792 Initializes variable store area for non-volatile and volatile variable.
1794 @param ImageHandle The Image handle of this driver.
1795 @param SystemTable The pointer of EFI_SYSTEM_TABLE.
1797 @retval EFI_SUCCESS Function successfully executed.
1798 @retval EFI_OUT_OF_RESOURCES Fail to allocate enough memory resource.
1802 VariableCommonInitialize (
1803 IN EFI_HANDLE ImageHandle
,
1804 IN EFI_SYSTEM_TABLE
*SystemTable
1808 EFI_FIRMWARE_VOLUME_HEADER
*FwVolHeader
;
1810 VARIABLE_STORE_HEADER
*VolatileVariableStore
;
1811 VARIABLE_STORE_HEADER
*VariableStoreHeader
;
1812 VARIABLE_HEADER
*NextVariable
;
1814 EFI_PHYSICAL_ADDRESS FvVolHdr
;
1815 UINT64 TempVariableStoreHeader
;
1816 EFI_GCD_MEMORY_SPACE_DESCRIPTOR GcdDescriptor
;
1821 UINT64 VariableStoreBase
;
1822 UINT64 VariableStoreLength
;
1823 EFI_EVENT ReadyToBootEvent
;
1825 Status
= EFI_SUCCESS
;
1827 // Allocate runtime memory for variable driver global structure.
1829 mVariableModuleGlobal
= AllocateRuntimePool (sizeof (VARIABLE_MODULE_GLOBAL
));
1830 if (mVariableModuleGlobal
== NULL
) {
1831 return EFI_OUT_OF_RESOURCES
;
1834 EfiInitializeLock(&mVariableModuleGlobal
->VariableGlobal
.VariableServicesLock
, TPL_NOTIFY
);
1835 mVariableModuleGlobal
->VariableGlobal
.ReentrantState
= 0;
1838 // Allocate memory for volatile variable store
1840 VolatileVariableStore
= AllocateRuntimePool (FixedPcdGet32(PcdVariableStoreSize
) + FixedPcdGet32(PcdMaxVariableSize
));
1841 if (VolatileVariableStore
== NULL
) {
1842 FreePool (mVariableModuleGlobal
);
1843 return EFI_OUT_OF_RESOURCES
;
1846 SetMem (VolatileVariableStore
, FixedPcdGet32(PcdVariableStoreSize
) + FixedPcdGet32(PcdMaxVariableSize
), 0xff);
1849 // Variable Specific Data
1851 mVariableModuleGlobal
->VariableGlobal
.VolatileVariableBase
= (EFI_PHYSICAL_ADDRESS
) (UINTN
) VolatileVariableStore
;
1852 mVariableModuleGlobal
->VolatileLastVariableOffset
= (UINTN
) GetStartPointer (VolatileVariableStore
) - (UINTN
) VolatileVariableStore
;
1854 VolatileVariableStore
->Signature
= VARIABLE_STORE_SIGNATURE
;
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
= (UINT64
) 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
;
1899 // Find the Correct Instance of the FV Block Service.
1902 CurrPtr
= (CHAR8
*) ((UINTN
) mVariableModuleGlobal
->VariableGlobal
.NonVolatileVariableBase
);
1903 while (EfiFvbGetPhysicalAddress (Instance
, &FvVolHdr
) == EFI_SUCCESS
) {
1904 FwVolHeader
= (EFI_FIRMWARE_VOLUME_HEADER
*) ((UINTN
) FvVolHdr
);
1905 if (CurrPtr
>= (CHAR8
*) FwVolHeader
&& CurrPtr
< (((CHAR8
*) FwVolHeader
) + FwVolHeader
->FvLength
)) {
1906 mVariableModuleGlobal
->FvbInstance
= Instance
;
1913 VariableStoreHeader
= (VARIABLE_STORE_HEADER
*) CurrPtr
;
1914 if (GetVariableStoreStatus (VariableStoreHeader
) == EfiValid
) {
1915 if (~VariableStoreHeader
->Size
== 0) {
1916 Status
= UpdateVariableStore (
1917 &mVariableModuleGlobal
->VariableGlobal
,
1920 mVariableModuleGlobal
->FvbInstance
,
1921 (UINTN
) &VariableStoreHeader
->Size
,
1923 (UINT8
*) &VariableStoreLength
1926 // As Variables are stored in NV storage, which are slow devices,such as flash.
1927 // Variable operation may skip checking variable program result to improve performance,
1928 // We can assume Variable program is OK through some check point.
1929 // Variable Store Size Setting should be the first Variable write operation,
1930 // We can assume all Read/Write is OK if we can set Variable store size successfully.
1931 // If write fail, we will assert here
1933 ASSERT(VariableStoreHeader
->Size
== VariableStoreLength
);
1935 if (EFI_ERROR (Status
)) {
1940 mVariableModuleGlobal
->VariableGlobal
.NonVolatileVariableBase
= (EFI_PHYSICAL_ADDRESS
) ((UINTN
) CurrPtr
);
1942 // Parse non-volatile variable data and get last variable offset
1944 NextVariable
= GetStartPointer ((VARIABLE_STORE_HEADER
*) CurrPtr
);
1945 Status
= EFI_SUCCESS
;
1947 while (IsValidVariableHeader (NextVariable
)) {
1948 NextVariable
= GetNextVariablePtr (NextVariable
);
1951 mVariableModuleGlobal
->NonVolatileLastVariableOffset
= (UINTN
) NextVariable
- (UINTN
) CurrPtr
;
1954 // Check if the free area is really free.
1956 for (Index
= mVariableModuleGlobal
->NonVolatileLastVariableOffset
; Index
< VariableStoreHeader
->Size
; Index
++) {
1957 Data
= ((UINT8
*) (UINTN
) mVariableModuleGlobal
->VariableGlobal
.NonVolatileVariableBase
)[Index
];
1960 // There must be something wrong in variable store, do reclaim operation.
1963 mVariableModuleGlobal
->VariableGlobal
.NonVolatileVariableBase
,
1964 &mVariableModuleGlobal
->NonVolatileLastVariableOffset
,
1969 if (EFI_ERROR (Status
)) {
1978 // Register the event handling function to reclaim variable for OS usage.
1980 Status
= EfiCreateEventReadyToBootEx (
1989 if (EFI_ERROR (Status
)) {
1990 FreePool (mVariableModuleGlobal
);
1991 FreePool (VolatileVariableStore
);
1998 Notification function of EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE
2000 This is a notification function registered on EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE event.
2001 It convers pointer to new virtual address.
2003 @param Event Event whose notification function is being invoked
2004 @param Context Pointer to the notification function's context
2009 VariableClassAddressChangeEvent (
2016 (VOID
**) &mVariableModuleGlobal
->VariableGlobal
.NonVolatileVariableBase
2020 (VOID
**) &mVariableModuleGlobal
->VariableGlobal
.VolatileVariableBase
2022 EfiConvertPointer (0x0, (VOID
**) &mVariableModuleGlobal
);
2027 Variable Driver main entry point. The Variable driver places the 4 EFI
2028 runtime services in the EFI System Table and installs arch protocols
2029 for variable read and write services being availible. It also registers
2030 notification function for EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE event.
2032 @param[in] ImageHandle The firmware allocated handle for the EFI image.
2033 @param[in] SystemTable A pointer to the EFI System Table.
2035 @retval EFI_SUCCESS Variable service successfully initialized.
2040 VariableServiceInitialize (
2041 IN EFI_HANDLE ImageHandle
,
2042 IN EFI_SYSTEM_TABLE
*SystemTable
2047 Status
= VariableCommonInitialize (ImageHandle
, SystemTable
);
2048 ASSERT_EFI_ERROR (Status
);
2050 SystemTable
->RuntimeServices
->GetVariable
= RuntimeServiceGetVariable
;
2051 SystemTable
->RuntimeServices
->GetNextVariableName
= RuntimeServiceGetNextVariableName
;
2052 SystemTable
->RuntimeServices
->SetVariable
= RuntimeServiceSetVariable
;
2053 SystemTable
->RuntimeServices
->QueryVariableInfo
= RuntimeServiceQueryVariableInfo
;
2056 // Now install the Variable Runtime Architectural Protocol on a new handle
2058 Status
= gBS
->InstallMultipleProtocolInterfaces (
2060 &gEfiVariableArchProtocolGuid
, NULL
,
2061 &gEfiVariableWriteArchProtocolGuid
, NULL
,
2064 ASSERT_EFI_ERROR (Status
);
2066 Status
= gBS
->CreateEvent (
2067 EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE
,
2069 VariableClassAddressChangeEvent
,
2071 &mVirtualAddressChangeEvent
2073 ASSERT_EFI_ERROR (Status
);