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.
20 VARIABLE_MODULE_GLOBAL
*mVariableModuleGlobal
;
21 EFI_EVENT mVirtualAddressChangeEvent
= NULL
;
22 EFI_HANDLE mHandle
= NULL
;
26 // This is a temperary function which will be removed
27 // when EfiAcquireLock in UefiLib can handle the
28 // the call in UEFI Runtimer driver in RT phase.
31 AcquireLockOnlyAtBootTime (
35 if (!EfiAtRuntime ()) {
36 EfiAcquireLock (Lock
);
41 // This is a temperary function which will be removed
42 // when EfiAcquireLock in UefiLib can handle the
43 // the call in UEFI Runtimer driver in RT phase.
46 ReleaseLockOnlyAtBootTime (
50 if (!EfiAtRuntime ()) {
51 EfiReleaseLock (Lock
);
56 GLOBAL_REMOVE_IF_UNREFERENCED VARIABLE_INFO_ENTRY
*gVariableInfo
= NULL
;
60 Routine used to track statistical information about variable usage.
61 The data is stored in the EFI system table so it can be accessed later.
62 VariableInfo.efi can dump out the table. Only Boot Services variable
63 accesses are tracked by this code. The PcdVariableCollectStatistics
64 build flag controls if this feature is enabled.
66 A read that hits in the cache will have Read and Cache true for
67 the transaction. Data is allocated by this routine, but never
70 @param[in] VariableName Name of the Variable to track
71 @param[in] VendorGuid Guid of the Variable to track
72 @param[in] Volatile TRUE if volatile FALSE if non-volatile
73 @param[in] Read TRUE if GetVariable() was called
74 @param[in] Write TRUE if SetVariable() was called
75 @param[in] Delete TRUE if deleted via SetVariable()
76 @param[in] Cache TRUE for a cache hit.
81 IN CHAR16
*VariableName
,
82 IN EFI_GUID
*VendorGuid
,
90 VARIABLE_INFO_ENTRY
*Entry
;
92 if (FeaturePcdGet (PcdVariableCollectStatistics
)) {
94 if (EfiAtRuntime ()) {
95 // Don't collect statistics at runtime
99 if (gVariableInfo
== NULL
) {
101 // on the first call allocate a entry and place a pointer to it in
102 // the EFI System Table
104 gVariableInfo
= AllocateZeroPool (sizeof (VARIABLE_INFO_ENTRY
));
105 ASSERT (gVariableInfo
!= NULL
);
107 CopyGuid (&gVariableInfo
->VendorGuid
, VendorGuid
);
108 gVariableInfo
->Name
= AllocatePool (StrLen (VariableName
));
109 StrCpy (gVariableInfo
->Name
, VariableName
);
110 gVariableInfo
->Volatile
= Volatile
;
112 gBS
->InstallConfigurationTable (&gEfiVariableInfoGuid
, gVariableInfo
);
116 for (Entry
= gVariableInfo
; Entry
!= NULL
; Entry
= Entry
->Next
) {
117 if (CompareGuid (VendorGuid
, &Entry
->VendorGuid
)) {
118 if (StrCmp (VariableName
, Entry
->Name
) == 0) {
126 Entry
->DeleteCount
++;
136 if (Entry
->Next
== NULL
) {
138 // If the entry is not in the table add it.
139 // Next iteration of the loop will fill in the data
141 Entry
->Next
= AllocateZeroPool (sizeof (VARIABLE_INFO_ENTRY
));
142 ASSERT (Entry
->Next
!= NULL
);
144 CopyGuid (&Entry
->Next
->VendorGuid
, VendorGuid
);
145 Entry
->Next
->Name
= AllocatePool (StrLen (VariableName
));
146 StrCpy (Entry
->Next
->Name
, VariableName
);
147 Entry
->Next
->Volatile
= Volatile
;
156 IsValidVariableHeader (
157 IN VARIABLE_HEADER
*Variable
163 This code checks if variable header is valid or not.
166 Variable Pointer to the Variable Header.
169 TRUE Variable header is valid.
170 FALSE Variable header is not valid.
174 if (Variable
== NULL
|| Variable
->StartId
!= VARIABLE_DATA
) {
183 UpdateVariableStore (
184 IN VARIABLE_GLOBAL
*Global
,
186 IN BOOLEAN SetByIndex
,
188 IN UINTN DataPtrIndex
,
196 This function writes data to the FWH at the correct LBA even if the LBAs
201 Global - Pointer to VARAIBLE_GLOBAL structure
202 Volatile - If the Variable is Volatile or Non-Volatile
203 SetByIndex - TRUE: Target pointer is given as index
204 FALSE: Target pointer is absolute
205 Instance - Instance of FV Block services
206 DataPtrIndex - Pointer to the Data from the end of VARIABLE_STORE_HEADER
208 DataSize - Size of data to be written.
209 Buffer - Pointer to the buffer from which data is written
213 EFI_INVALID_PARAMETER - Parameters not valid
214 EFI_SUCCESS - Variable store successfully updated
218 EFI_FV_BLOCK_MAP_ENTRY
*PtrBlockMapEntry
;
226 EFI_FIRMWARE_VOLUME_HEADER
*FwVolHeader
;
227 VARIABLE_STORE_HEADER
*VolatileBase
;
228 EFI_PHYSICAL_ADDRESS FvVolHdr
;
229 EFI_PHYSICAL_ADDRESS DataPtr
;
233 DataPtr
= DataPtrIndex
;
236 // Check if the Data is Volatile
239 EfiFvbGetPhysicalAddress (Instance
, &FvVolHdr
);
240 FwVolHeader
= (EFI_FIRMWARE_VOLUME_HEADER
*) ((UINTN
) FvVolHdr
);
242 // Data Pointer should point to the actual Address where data is to be
246 DataPtr
+= mVariableModuleGlobal
->VariableGlobal
.NonVolatileVariableBase
;
249 if ((DataPtr
+ DataSize
) >= ((EFI_PHYSICAL_ADDRESS
) (UINTN
) ((UINT8
*) FwVolHeader
+ FwVolHeader
->FvLength
))) {
250 return EFI_INVALID_PARAMETER
;
254 // Data Pointer should point to the actual Address where data is to be
257 VolatileBase
= (VARIABLE_STORE_HEADER
*) ((UINTN
) mVariableModuleGlobal
->VariableGlobal
.VolatileVariableBase
);
259 DataPtr
+= mVariableModuleGlobal
->VariableGlobal
.VolatileVariableBase
;
262 if ((DataPtr
+ DataSize
) >= ((UINTN
) ((UINT8
*) VolatileBase
+ VolatileBase
->Size
))) {
263 return EFI_INVALID_PARAMETER
;
267 // If Volatile Variable just do a simple mem copy.
269 CopyMem ((UINT8
*)(UINTN
)DataPtr
, Buffer
, DataSize
);
274 // If we are here we are dealing with Non-Volatile Variables
276 LinearOffset
= (UINTN
) FwVolHeader
;
277 CurrWritePtr
= (UINTN
) DataPtr
;
278 CurrWriteSize
= DataSize
;
282 if (CurrWritePtr
< LinearOffset
) {
283 return EFI_INVALID_PARAMETER
;
286 for (PtrBlockMapEntry
= FwVolHeader
->BlockMap
; PtrBlockMapEntry
->NumBlocks
!= 0; PtrBlockMapEntry
++) {
287 for (BlockIndex2
= 0; BlockIndex2
< PtrBlockMapEntry
->NumBlocks
; BlockIndex2
++) {
289 // Check to see if the Variable Writes are spanning through multiple
292 if ((CurrWritePtr
>= LinearOffset
) && (CurrWritePtr
< LinearOffset
+ PtrBlockMapEntry
->Length
)) {
293 if ((CurrWritePtr
+ CurrWriteSize
) <= (LinearOffset
+ PtrBlockMapEntry
->Length
)) {
294 Status
= EfiFvbWriteBlock (
297 (UINTN
) (CurrWritePtr
- LinearOffset
),
303 Size
= (UINT32
) (LinearOffset
+ PtrBlockMapEntry
->Length
- CurrWritePtr
);
304 Status
= EfiFvbWriteBlock (
307 (UINTN
) (CurrWritePtr
- LinearOffset
),
311 if (EFI_ERROR (Status
)) {
315 CurrWritePtr
= LinearOffset
+ PtrBlockMapEntry
->Length
;
316 CurrBuffer
= CurrBuffer
+ Size
;
317 CurrWriteSize
= CurrWriteSize
- Size
;
321 LinearOffset
+= PtrBlockMapEntry
->Length
;
330 VARIABLE_STORE_STATUS
331 GetVariableStoreStatus (
332 IN VARIABLE_STORE_HEADER
*VarStoreHeader
338 This code gets the current status of Variable Store.
342 VarStoreHeader Pointer to the Variable Store Header.
346 EfiRaw Variable store status is raw
347 EfiValid Variable store status is valid
348 EfiInvalid Variable store status is invalid
352 if (VarStoreHeader
->Signature
== VARIABLE_STORE_SIGNATURE
&&
353 VarStoreHeader
->Format
== VARIABLE_STORE_FORMATTED
&&
354 VarStoreHeader
->State
== VARIABLE_STORE_HEALTHY
358 } else if (VarStoreHeader
->Signature
== 0xffffffff &&
359 VarStoreHeader
->Size
== 0xffffffff &&
360 VarStoreHeader
->Format
== 0xff &&
361 VarStoreHeader
->State
== 0xff
373 IN VARIABLE_HEADER
*Variable
379 This code gets the size of name of variable.
383 Variable Pointer to the Variable Header.
387 UINTN Size of variable in bytes
391 if (Variable
->State
== (UINT8
) (-1) ||
392 Variable
->DataSize
== (UINT32
) -1 ||
393 Variable
->NameSize
== (UINT32
) -1 ||
394 Variable
->Attributes
== (UINT32
) -1) {
397 return (UINTN
) Variable
->NameSize
;
402 IN VARIABLE_HEADER
*Variable
408 This code gets the size of name of variable.
412 Variable Pointer to the Variable Header.
416 UINTN Size of variable in bytes
420 if (Variable
->State
== (UINT8
) -1 ||
421 Variable
->DataSize
== (UINT32
) -1 ||
422 Variable
->NameSize
== (UINT32
) -1 ||
423 Variable
->Attributes
== (UINT32
) -1) {
426 return (UINTN
) Variable
->DataSize
;
431 IN VARIABLE_HEADER
*Variable
437 This code gets the pointer to the variable name.
441 Variable Pointer to the Variable Header.
445 CHAR16* Pointer to Variable Name
450 return (CHAR16
*) (Variable
+ 1);
455 IN VARIABLE_HEADER
*Variable
461 This code gets the pointer to the variable data.
465 Variable Pointer to the Variable Header.
469 UINT8* Pointer to Variable Data
476 // Be careful about pad size for alignment
478 Value
= (UINTN
) GetVariableNamePtr (Variable
);
479 Value
+= NameSizeOfVariable (Variable
);
480 Value
+= GET_PAD_SIZE (NameSizeOfVariable (Variable
));
482 return (UINT8
*) Value
;
488 IN VARIABLE_HEADER
*Variable
494 This code gets the pointer to the next variable header.
498 Variable Pointer to the Variable Header.
502 VARIABLE_HEADER* Pointer to next variable header.
508 if (!IsValidVariableHeader (Variable
)) {
512 Value
= (UINTN
) GetVariableDataPtr (Variable
);
513 Value
+= DataSizeOfVariable (Variable
);
514 Value
+= GET_PAD_SIZE (DataSizeOfVariable (Variable
));
517 // Be careful about pad size for alignment
519 return (VARIABLE_HEADER
*) HEADER_ALIGN (Value
);
524 IN VARIABLE_STORE_HEADER
*VarStoreHeader
530 This code gets the pointer to the first variable memory pointer byte
534 VarStoreHeader Pointer to the Variable Store Header.
538 VARIABLE_HEADER* Pointer to last unavailable Variable Header
543 // The end of variable store
545 return (VARIABLE_HEADER
*) HEADER_ALIGN (VarStoreHeader
+ 1);
550 IN VARIABLE_STORE_HEADER
*VarStoreHeader
556 This code gets the pointer to the last variable memory pointer byte
560 VarStoreHeader Pointer to the Variable Store Header.
564 VARIABLE_HEADER* Pointer to last unavailable Variable Header
569 // The end of variable store
571 return (VARIABLE_HEADER
*) HEADER_ALIGN ((UINTN
) VarStoreHeader
+ VarStoreHeader
->Size
);
577 IN EFI_PHYSICAL_ADDRESS VariableBase
,
578 OUT UINTN
*LastVariableOffset
,
579 IN BOOLEAN IsVolatile
,
580 IN VARIABLE_HEADER
*UpdatingVariable
586 Variable store garbage collection and reclaim operation
590 VariableBase Base address of variable store
591 LastVariableOffset Offset of last variable
592 IsVolatile The variable store is volatile or not,
593 if it is non-volatile, need FTW
601 VARIABLE_HEADER
*Variable
;
602 VARIABLE_HEADER
*AddedVariable
;
603 VARIABLE_HEADER
*NextVariable
;
604 VARIABLE_HEADER
*NextAddedVariable
;
605 VARIABLE_STORE_HEADER
*VariableStoreHeader
;
607 UINTN MaximumBufferSize
;
609 UINTN VariableNameSize
;
610 UINTN UpdatingVariableNameSize
;
617 CHAR16
*VariableNamePtr
;
618 CHAR16
*UpdatingVariableNamePtr
;
620 VariableStoreHeader
= (VARIABLE_STORE_HEADER
*) ((UINTN
) VariableBase
);
623 // Start Pointers for the variable.
625 Variable
= GetStartPointer (VariableStoreHeader
);
626 MaximumBufferSize
= sizeof (VARIABLE_STORE_HEADER
);
628 while (IsValidVariableHeader (Variable
)) {
629 NextVariable
= GetNextVariablePtr (Variable
);
630 if (Variable
->State
== VAR_ADDED
||
631 Variable
->State
== (VAR_IN_DELETED_TRANSITION
& VAR_ADDED
)
633 VariableSize
= (UINTN
) NextVariable
- (UINTN
) Variable
;
634 MaximumBufferSize
+= VariableSize
;
637 Variable
= NextVariable
;
641 // Reserve the 1 Bytes with Oxff to identify the
642 // end of the variable buffer.
644 MaximumBufferSize
+= 1;
645 ValidBuffer
= AllocatePool (MaximumBufferSize
);
646 if (ValidBuffer
== NULL
) {
647 return EFI_OUT_OF_RESOURCES
;
650 SetMem (ValidBuffer
, MaximumBufferSize
, 0xff);
653 // Copy variable store header
655 CopyMem (ValidBuffer
, VariableStoreHeader
, sizeof (VARIABLE_STORE_HEADER
));
656 CurrPtr
= (UINT8
*) GetStartPointer ((VARIABLE_STORE_HEADER
*) ValidBuffer
);
659 // Start Pointers for the variable.
663 // Reinstall all ADDED variables as long as they are not identical to Updating Variable
665 Variable
= GetStartPointer (VariableStoreHeader
);
666 while (IsValidVariableHeader (Variable
)) {
667 NextVariable
= GetNextVariablePtr (Variable
);
668 if (Variable
->State
== VAR_ADDED
) {
669 if (UpdatingVariable
!= NULL
) {
670 if (UpdatingVariable
== Variable
) {
671 Variable
= NextVariable
;
675 VariableNameSize
= NameSizeOfVariable(Variable
);
676 UpdatingVariableNameSize
= NameSizeOfVariable(UpdatingVariable
);
678 VariableNamePtr
= GetVariableNamePtr (Variable
);
679 UpdatingVariableNamePtr
= GetVariableNamePtr (UpdatingVariable
);
680 if (CompareGuid (&Variable
->VendorGuid
, &UpdatingVariable
->VendorGuid
) &&
681 VariableNameSize
== UpdatingVariableNameSize
&&
682 CompareMem (VariableNamePtr
, UpdatingVariableNamePtr
, VariableNameSize
) == 0 ) {
683 Variable
= NextVariable
;
687 VariableSize
= (UINTN
) NextVariable
- (UINTN
) Variable
;
688 CopyMem (CurrPtr
, (UINT8
*) Variable
, VariableSize
);
689 CurrPtr
+= VariableSize
;
691 Variable
= NextVariable
;
695 // Reinstall the variable being updated if it is not NULL
697 if (UpdatingVariable
!= NULL
) {
698 VariableSize
= (UINTN
)(GetNextVariablePtr (UpdatingVariable
)) - (UINTN
)UpdatingVariable
;
699 CopyMem (CurrPtr
, (UINT8
*) UpdatingVariable
, VariableSize
);
700 CurrPtr
+= VariableSize
;
704 // Reinstall all in delete transition variables
706 Variable
= GetStartPointer (VariableStoreHeader
);
707 while (IsValidVariableHeader (Variable
)) {
708 NextVariable
= GetNextVariablePtr (Variable
);
709 if (Variable
!= UpdatingVariable
&& Variable
->State
== (VAR_IN_DELETED_TRANSITION
& VAR_ADDED
)) {
712 // Buffer has cached all ADDED variable.
713 // Per IN_DELETED variable, we have to guarantee that
714 // no ADDED one in previous buffer.
718 AddedVariable
= GetStartPointer ((VARIABLE_STORE_HEADER
*) ValidBuffer
);
719 while (IsValidVariableHeader (AddedVariable
)) {
720 NextAddedVariable
= GetNextVariablePtr (AddedVariable
);
721 NameSize
= NameSizeOfVariable (AddedVariable
);
722 if (CompareGuid (&AddedVariable
->VendorGuid
, &Variable
->VendorGuid
) &&
723 NameSize
== NameSizeOfVariable (Variable
)
725 Point0
= (VOID
*) GetVariableNamePtr (AddedVariable
);
726 Point1
= (VOID
*) GetVariableNamePtr (Variable
);
727 if (CompareMem (Point0
, Point1
, NameSizeOfVariable (AddedVariable
)) == 0) {
732 AddedVariable
= NextAddedVariable
;
736 // Promote VAR_IN_DELETED_TRANSITION to VAR_ADDED
738 VariableSize
= (UINTN
) NextVariable
- (UINTN
) Variable
;
739 CopyMem (CurrPtr
, (UINT8
*) Variable
, VariableSize
);
740 ((VARIABLE_HEADER
*) CurrPtr
)->State
= VAR_ADDED
;
741 CurrPtr
+= VariableSize
;
745 Variable
= NextVariable
;
750 // If volatile variable store, just copy valid buffer
752 SetMem ((UINT8
*) (UINTN
) VariableBase
, VariableStoreHeader
->Size
, 0xff);
753 CopyMem ((UINT8
*) (UINTN
) VariableBase
, ValidBuffer
, (UINTN
) (CurrPtr
- (UINT8
*) ValidBuffer
));
754 Status
= EFI_SUCCESS
;
757 // If non-volatile variable store, perform FTW here.
759 Status
= FtwVariableSpace (
762 (UINTN
) (CurrPtr
- (UINT8
*) ValidBuffer
)
765 if (!EFI_ERROR (Status
)) {
766 *LastVariableOffset
= (UINTN
) (CurrPtr
- (UINT8
*) ValidBuffer
);
768 *LastVariableOffset
= 0;
771 FreePool (ValidBuffer
);
778 // The current Hii implementation accesses this variable a larg # of times on every boot.
779 // Other common variables are only accessed a single time. This is why this cache algorithm
780 // only targets a single variable. Probably to get an performance improvement out of
781 // a Cache you would need a cache that improves the search performance for a variable.
783 VARIABLE_CACHE_ENTRY mVariableCache
[] = {
785 &gEfiGlobalVariableGuid
,
795 Update the Cache with Variable information. These are the same
796 arguments as the EFI Variable services.
798 @param[in] VariableName Name of variable
799 @param[in] VendorGuid Guid of variable
800 @param[in] Attribute Attribue of the variable
801 @param[in] DataSize Size of data. 0 means delete
802 @param[in] Data Variable data
806 UpdateVariableCache (
807 IN CHAR16
*VariableName
,
808 IN EFI_GUID
*VendorGuid
,
809 IN UINT32 Attributes
,
814 VARIABLE_CACHE_ENTRY
*Entry
;
817 if (EfiAtRuntime ()) {
818 // Don't use the cache at runtime
822 for (Index
= 0, Entry
= mVariableCache
; Index
< sizeof (mVariableCache
)/sizeof (VARIABLE_CACHE_ENTRY
); Index
++, Entry
++) {
823 if (CompareGuid (VendorGuid
, Entry
->Guid
)) {
824 if (StrCmp (VariableName
, Entry
->Name
) == 0) {
825 Entry
->Attributes
= Attributes
;
828 if (Entry
->DataSize
!= 0) {
829 FreePool (Entry
->Data
);
831 Entry
->DataSize
= DataSize
;
832 } else if (DataSize
== Entry
->DataSize
) {
833 CopyMem (Entry
->Data
, Data
, DataSize
);
835 Entry
->Data
= AllocatePool (DataSize
);
836 Entry
->DataSize
= DataSize
;
837 CopyMem (Entry
->Data
, Data
, DataSize
);
846 Search the cache to see if the variable is in the cache.
848 @param[in] VariableName Name of variable
849 @param[in] VendorGuid Guid of variable
850 @param[in] Attribute Attribue returned
851 @param[in] DataSize Size of data returned
852 @param[in] Data Variable data returned
854 @retval EFI_SUCCESS VariableGuid & VariableName data was returned.
855 @retval other Not found.
859 FindVariableInCache (
860 IN CHAR16
*VariableName
,
861 IN EFI_GUID
*VendorGuid
,
862 OUT UINT32
*Attributes OPTIONAL
,
863 IN OUT UINTN
*DataSize
,
867 VARIABLE_CACHE_ENTRY
*Entry
;
870 if (EfiAtRuntime ()) {
871 // Don't use the cache at runtime
872 return EFI_NOT_FOUND
;
875 for (Index
= 0, Entry
= mVariableCache
; Index
< sizeof (mVariableCache
)/sizeof (VARIABLE_CACHE_ENTRY
); Index
++, Entry
++) {
876 if (CompareGuid (VendorGuid
, Entry
->Guid
)) {
877 if (StrCmp (VariableName
, Entry
->Name
) == 0) {
878 if (Entry
->DataSize
== 0) {
879 // Variable was deleted so return not found
880 return EFI_NOT_FOUND
;
881 } else if (Entry
->DataSize
> *DataSize
) {
882 // If the buffer is too small return correct size
883 *DataSize
= Entry
->DataSize
;
884 return EFI_BUFFER_TOO_SMALL
;
886 *DataSize
= Entry
->DataSize
;
888 CopyMem (Data
, Entry
->Data
, Entry
->DataSize
);
889 if (Attributes
!= NULL
) {
890 *Attributes
= Entry
->Attributes
;
898 return EFI_NOT_FOUND
;
904 IN CHAR16
*VariableName
,
905 IN EFI_GUID
*VendorGuid
,
906 OUT VARIABLE_POINTER_TRACK
*PtrTrack
,
907 IN VARIABLE_GLOBAL
*Global
913 This code finds variable in storage blocks (Volatile or Non-Volatile)
917 VariableName Name of the variable to be found
918 VendorGuid Vendor GUID to be found.
919 PtrTrack Variable Track Pointer structure that contains
920 Variable Information.
921 Contains the pointer of Variable header.
922 Global VARIABLE_GLOBAL pointer
930 VARIABLE_HEADER
*Variable
[2];
931 VARIABLE_HEADER
*InDeletedVariable
;
932 VARIABLE_STORE_HEADER
*VariableStoreHeader
[2];
933 UINTN InDeletedStorageIndex
;
938 // 0: Volatile, 1: Non-Volatile
939 // The index and attributes mapping must be kept in this order as RuntimeServiceGetNextVariableName
940 // make use of this mapping to implement search algorithme.
942 VariableStoreHeader
[0] = (VARIABLE_STORE_HEADER
*) ((UINTN
) mVariableModuleGlobal
->VariableGlobal
.VolatileVariableBase
);
943 VariableStoreHeader
[1] = (VARIABLE_STORE_HEADER
*) ((UINTN
) mVariableModuleGlobal
->VariableGlobal
.NonVolatileVariableBase
);
946 // Start Pointers for the variable.
947 // Actual Data Pointer where data can be written.
949 Variable
[0] = GetStartPointer (VariableStoreHeader
[0]);
950 Variable
[1] = GetStartPointer (VariableStoreHeader
[1]);
952 if (VariableName
[0] != 0 && VendorGuid
== NULL
) {
953 return EFI_INVALID_PARAMETER
;
957 // Find the variable by walk through volatile and then non-volatile variable store
959 InDeletedVariable
= NULL
;
960 InDeletedStorageIndex
= 0;
961 for (Index
= 0; Index
< 2; Index
++) {
962 while (IsValidVariableHeader (Variable
[Index
]) && (Variable
[Index
] <= GetEndPointer (VariableStoreHeader
[Index
]))) {
963 if (Variable
[Index
]->State
== VAR_ADDED
||
964 Variable
[Index
]->State
== (VAR_IN_DELETED_TRANSITION
& VAR_ADDED
)
966 if (!EfiAtRuntime () || (Variable
[Index
]->Attributes
& EFI_VARIABLE_RUNTIME_ACCESS
)) {
967 if (VariableName
[0] == 0) {
968 if (Variable
[Index
]->State
== (VAR_IN_DELETED_TRANSITION
& VAR_ADDED
)) {
969 InDeletedVariable
= Variable
[Index
];
970 InDeletedStorageIndex
= Index
;
972 PtrTrack
->StartPtr
= GetStartPointer (VariableStoreHeader
[Index
]);
973 PtrTrack
->EndPtr
= GetEndPointer (VariableStoreHeader
[Index
]);
974 PtrTrack
->CurrPtr
= Variable
[Index
];
975 PtrTrack
->Volatile
= (BOOLEAN
)(Index
== 0);
980 if (CompareGuid (VendorGuid
, &Variable
[Index
]->VendorGuid
)) {
981 Point
= (VOID
*) GetVariableNamePtr (Variable
[Index
]);
983 ASSERT (NameSizeOfVariable (Variable
[Index
]) != 0);
984 if (!CompareMem (VariableName
, Point
, NameSizeOfVariable (Variable
[Index
]))) {
985 if (Variable
[Index
]->State
== (VAR_IN_DELETED_TRANSITION
& VAR_ADDED
)) {
986 InDeletedVariable
= Variable
[Index
];
987 InDeletedStorageIndex
= Index
;
989 PtrTrack
->StartPtr
= GetStartPointer (VariableStoreHeader
[Index
]);
990 PtrTrack
->EndPtr
= GetEndPointer (VariableStoreHeader
[Index
]);
991 PtrTrack
->CurrPtr
= Variable
[Index
];
992 PtrTrack
->Volatile
= (BOOLEAN
)(Index
== 0);
1002 Variable
[Index
] = GetNextVariablePtr (Variable
[Index
]);
1004 if (InDeletedVariable
!= NULL
) {
1005 PtrTrack
->StartPtr
= GetStartPointer (VariableStoreHeader
[InDeletedStorageIndex
]);
1006 PtrTrack
->EndPtr
= GetEndPointer (VariableStoreHeader
[InDeletedStorageIndex
]);
1007 PtrTrack
->CurrPtr
= InDeletedVariable
;
1008 PtrTrack
->Volatile
= (BOOLEAN
)(InDeletedStorageIndex
== 0);
1012 PtrTrack
->CurrPtr
= NULL
;
1013 return EFI_NOT_FOUND
;
1020 Routine Description:
1022 This code finds variable in storage blocks (Volatile or Non-Volatile)
1026 VariableName Name of Variable to be found
1027 VendorGuid Variable vendor GUID
1028 Attributes OPTIONAL Attribute value of the variable found
1029 DataSize Size of Data found. If size is less than the
1030 data, this value contains the required size.
1032 Global Pointer to VARIABLE_GLOBAL structure
1033 Instance Instance of the Firmware Volume.
1037 EFI_INVALID_PARAMETER - Invalid parameter
1038 EFI_SUCCESS - Find the specified variable
1039 EFI_NOT_FOUND - Not found
1040 EFI_BUFFER_TO_SMALL - DataSize is too small for the result
1046 RuntimeServiceGetVariable (
1047 IN CHAR16
*VariableName
,
1048 IN EFI_GUID
*VendorGuid
,
1049 OUT UINT32
*Attributes OPTIONAL
,
1050 IN OUT UINTN
*DataSize
,
1055 VARIABLE_POINTER_TRACK Variable
;
1058 if (VariableName
== NULL
|| VendorGuid
== NULL
|| DataSize
== NULL
) {
1059 return EFI_INVALID_PARAMETER
;
1062 AcquireLockOnlyAtBootTime(&mVariableModuleGlobal
->VariableGlobal
.VariableServicesLock
);
1065 // Find existing variable
1067 Status
= FindVariableInCache (VariableName
, VendorGuid
, Attributes
, DataSize
, Data
);
1068 if ((Status
== EFI_BUFFER_TOO_SMALL
) || (Status
== EFI_SUCCESS
)){
1070 UpdateVariableInfo (VariableName
, VendorGuid
, FALSE
, TRUE
, FALSE
, FALSE
, TRUE
);
1074 Status
= FindVariable (VariableName
, VendorGuid
, &Variable
, &mVariableModuleGlobal
->VariableGlobal
);
1075 if (Variable
.CurrPtr
== NULL
|| EFI_ERROR (Status
)) {
1082 VarDataSize
= DataSizeOfVariable (Variable
.CurrPtr
);
1083 ASSERT (VarDataSize
!= 0);
1085 if (*DataSize
>= VarDataSize
) {
1087 Status
= EFI_INVALID_PARAMETER
;
1091 CopyMem (Data
, GetVariableDataPtr (Variable
.CurrPtr
), VarDataSize
);
1092 if (Attributes
!= NULL
) {
1093 *Attributes
= Variable
.CurrPtr
->Attributes
;
1096 *DataSize
= VarDataSize
;
1097 UpdateVariableInfo (VariableName
, VendorGuid
, Variable
.Volatile
, TRUE
, FALSE
, FALSE
, FALSE
);
1098 UpdateVariableCache (VariableName
, VendorGuid
, Variable
.CurrPtr
->Attributes
, VarDataSize
, Data
);
1100 Status
= EFI_SUCCESS
;
1103 *DataSize
= VarDataSize
;
1104 Status
= EFI_BUFFER_TOO_SMALL
;
1109 ReleaseLockOnlyAtBootTime (&mVariableModuleGlobal
->VariableGlobal
.VariableServicesLock
);
1117 Routine Description:
1119 This code Finds the Next available variable
1123 VariableNameSize Size of the variable
1124 VariableName Pointer to variable name
1125 VendorGuid Variable Vendor Guid
1126 Global VARIABLE_GLOBAL structure pointer.
1127 Instance FV instance
1136 RuntimeServiceGetNextVariableName (
1137 IN OUT UINTN
*VariableNameSize
,
1138 IN OUT CHAR16
*VariableName
,
1139 IN OUT EFI_GUID
*VendorGuid
1142 VARIABLE_POINTER_TRACK Variable
;
1146 if (VariableNameSize
== NULL
|| VariableName
== NULL
|| VendorGuid
== NULL
) {
1147 return EFI_INVALID_PARAMETER
;
1150 AcquireLockOnlyAtBootTime(&mVariableModuleGlobal
->VariableGlobal
.VariableServicesLock
);
1152 Status
= FindVariable (VariableName
, VendorGuid
, &Variable
, &mVariableModuleGlobal
->VariableGlobal
);
1153 if (Variable
.CurrPtr
== NULL
|| EFI_ERROR (Status
)) {
1157 if (VariableName
[0] != 0) {
1159 // If variable name is not NULL, get next variable
1161 Variable
.CurrPtr
= GetNextVariablePtr (Variable
.CurrPtr
);
1166 // If both volatile and non-volatile variable store are parsed,
1169 if (Variable
.CurrPtr
>= Variable
.EndPtr
|| Variable
.CurrPtr
== NULL
) {
1170 Variable
.Volatile
= (BOOLEAN
) (Variable
.Volatile
^ ((BOOLEAN
) 0x1));
1171 if (!Variable
.Volatile
) {
1172 Variable
.StartPtr
= GetStartPointer ((VARIABLE_STORE_HEADER
*) (UINTN
) mVariableModuleGlobal
->VariableGlobal
.NonVolatileVariableBase
);
1173 Variable
.EndPtr
= GetEndPointer ((VARIABLE_STORE_HEADER
*) ((UINTN
) mVariableModuleGlobal
->VariableGlobal
.NonVolatileVariableBase
));
1175 Status
= EFI_NOT_FOUND
;
1179 Variable
.CurrPtr
= Variable
.StartPtr
;
1180 if (!IsValidVariableHeader (Variable
.CurrPtr
)) {
1185 // Variable is found
1187 if (IsValidVariableHeader (Variable
.CurrPtr
) && Variable
.CurrPtr
->State
== VAR_ADDED
) {
1188 if (!(EfiAtRuntime () && !(Variable
.CurrPtr
->Attributes
& EFI_VARIABLE_RUNTIME_ACCESS
))) {
1189 VarNameSize
= NameSizeOfVariable (Variable
.CurrPtr
);
1190 ASSERT (VarNameSize
!= 0);
1192 if (VarNameSize
<= *VariableNameSize
) {
1195 GetVariableNamePtr (Variable
.CurrPtr
),
1200 &Variable
.CurrPtr
->VendorGuid
,
1203 Status
= EFI_SUCCESS
;
1205 Status
= EFI_BUFFER_TOO_SMALL
;
1208 *VariableNameSize
= VarNameSize
;
1213 Variable
.CurrPtr
= GetNextVariablePtr (Variable
.CurrPtr
);
1217 ReleaseLockOnlyAtBootTime (&mVariableModuleGlobal
->VariableGlobal
.VariableServicesLock
);
1224 Routine Description:
1226 This code sets variable in storage blocks (Volatile or Non-Volatile)
1230 VariableName Name of Variable to be found
1231 VendorGuid Variable vendor GUID
1232 Attributes Attribute value of the variable found
1233 DataSize Size of Data found. If size is less than the
1234 data, this value contains the required size.
1236 Global Pointer to VARIABLE_GLOBAL structure
1237 VolatileOffset The offset of last volatile variable
1238 NonVolatileOffset The offset of last non-volatile variable
1239 Instance Instance of the Firmware Volume.
1243 EFI_INVALID_PARAMETER - Invalid parameter
1244 EFI_SUCCESS - Set successfully
1245 EFI_OUT_OF_RESOURCES - Resource not enough to set variable
1246 EFI_NOT_FOUND - Not found
1247 EFI_DEVICE_ERROR - Variable can not be saved due to hardware failure
1248 EFI_WRITE_PROTECTED - Variable is read-only
1253 RuntimeServiceSetVariable (
1254 IN CHAR16
*VariableName
,
1255 IN EFI_GUID
*VendorGuid
,
1256 IN UINT32 Attributes
,
1261 VARIABLE_POINTER_TRACK Variable
;
1263 VARIABLE_HEADER
*NextVariable
;
1265 UINTN VarNameOffset
;
1266 UINTN VarDataOffset
;
1270 UINTN
*VolatileOffset
;
1271 UINTN
*NonVolatileOffset
;
1274 EFI_PHYSICAL_ADDRESS Point
;
1277 // Check input parameters
1279 if (VariableName
== NULL
|| VariableName
[0] == 0 || VendorGuid
== NULL
) {
1280 return EFI_INVALID_PARAMETER
;
1283 // Make sure if runtime bit is set, boot service bit is set also
1285 if ((Attributes
& (EFI_VARIABLE_RUNTIME_ACCESS
| EFI_VARIABLE_BOOTSERVICE_ACCESS
)) == EFI_VARIABLE_RUNTIME_ACCESS
) {
1286 return EFI_INVALID_PARAMETER
;
1290 // The size of the VariableName, including the Unicode Null in bytes plus
1291 // the DataSize is limited to maximum size of MAX_HARDWARE_ERROR_VARIABLE_SIZE (32K)
1292 // bytes for HwErrRec, and MAX_VARIABLE_SIZE (1024) bytes for the others.
1294 if ((Attributes
& EFI_VARIABLE_HARDWARE_ERROR_RECORD
) == EFI_VARIABLE_HARDWARE_ERROR_RECORD
) {
1295 if ((DataSize
> MAX_HARDWARE_ERROR_VARIABLE_SIZE
) ||
1296 (sizeof (VARIABLE_HEADER
) + StrSize (VariableName
) + DataSize
> MAX_HARDWARE_ERROR_VARIABLE_SIZE
)) {
1297 return EFI_INVALID_PARAMETER
;
1301 // The size of the VariableName, including the Unicode Null in bytes plus
1302 // the DataSize is limited to maximum size of MAX_VARIABLE_SIZE (1024) bytes.
1304 if ((DataSize
> MAX_VARIABLE_SIZE
) ||
1305 (sizeof (VARIABLE_HEADER
) + StrSize (VariableName
) + DataSize
> MAX_VARIABLE_SIZE
)) {
1306 return EFI_INVALID_PARAMETER
;
1310 AcquireLockOnlyAtBootTime(&mVariableModuleGlobal
->VariableGlobal
.VariableServicesLock
);
1313 Instance
= mVariableModuleGlobal
->FvbInstance
;
1314 VolatileOffset
= &mVariableModuleGlobal
->VolatileLastVariableOffset
;
1317 // Consider reentrant in MCA/INIT/NMI. It needs be reupdated;
1319 if (1 < InterlockedIncrement (&mVariableModuleGlobal
->VariableGlobal
.ReentrantState
)) {
1320 Point
= mVariableModuleGlobal
->VariableGlobal
.NonVolatileVariableBase
;;
1322 // Parse non-volatile variable data and get last variable offset
1324 NextVariable
= GetStartPointer ((VARIABLE_STORE_HEADER
*) (UINTN
) Point
);
1325 while (IsValidVariableHeader (NextVariable
)) {
1326 NextVariable
= GetNextVariablePtr (NextVariable
);
1328 mVariableModuleGlobal
->NonVolatileLastVariableOffset
= (UINTN
) NextVariable
- (UINTN
) Point
;
1331 NonVolatileOffset
= &mVariableModuleGlobal
->NonVolatileLastVariableOffset
;
1335 // Check whether the input variable is already existed
1338 Status
= FindVariable (VariableName
, VendorGuid
, &Variable
, &mVariableModuleGlobal
->VariableGlobal
);
1339 if (Status
== EFI_SUCCESS
&& Variable
.CurrPtr
!= NULL
) {
1341 // Update/Delete existing variable
1343 Volatile
= Variable
.Volatile
;
1345 if (EfiAtRuntime ()) {
1347 // If EfiAtRuntime and the variable is Volatile and Runtime Access,
1348 // the volatile is ReadOnly, and SetVariable should be aborted and
1349 // return EFI_WRITE_PROTECTED.
1351 if (Variable
.Volatile
) {
1352 Status
= EFI_WRITE_PROTECTED
;
1356 // Only variable have NV attribute can be updated/deleted in Runtime
1358 if (!(Variable
.CurrPtr
->Attributes
& EFI_VARIABLE_NON_VOLATILE
)) {
1359 Status
= EFI_INVALID_PARAMETER
;
1364 // Setting a data variable with no access, or zero DataSize attributes
1365 // specified causes it to be deleted.
1367 if (DataSize
== 0 || (Attributes
& (EFI_VARIABLE_RUNTIME_ACCESS
| EFI_VARIABLE_BOOTSERVICE_ACCESS
)) == 0) {
1368 State
= Variable
.CurrPtr
->State
;
1369 State
&= VAR_DELETED
;
1371 Status
= UpdateVariableStore (
1372 &mVariableModuleGlobal
->VariableGlobal
,
1376 (UINTN
) &Variable
.CurrPtr
->State
,
1380 if (!EFI_ERROR (Status
)) {
1381 UpdateVariableInfo (VariableName
, VendorGuid
, Volatile
, FALSE
, FALSE
, TRUE
, FALSE
);
1382 UpdateVariableCache (VariableName
, VendorGuid
, Attributes
, DataSize
, Data
);
1387 // If the variable is marked valid and the same data has been passed in
1388 // then return to the caller immediately.
1390 if (DataSizeOfVariable (Variable
.CurrPtr
) == DataSize
&&
1391 (CompareMem (Data
, GetVariableDataPtr (Variable
.CurrPtr
), DataSize
) == 0)) {
1393 UpdateVariableInfo (VariableName
, VendorGuid
, Volatile
, FALSE
, TRUE
, FALSE
, FALSE
);
1394 Status
= EFI_SUCCESS
;
1396 } else if ((Variable
.CurrPtr
->State
== VAR_ADDED
) ||
1397 (Variable
.CurrPtr
->State
== (VAR_ADDED
& VAR_IN_DELETED_TRANSITION
))) {
1400 // Mark the old variable as in delete transition
1402 State
= Variable
.CurrPtr
->State
;
1403 State
&= VAR_IN_DELETED_TRANSITION
;
1405 Status
= UpdateVariableStore (
1406 &mVariableModuleGlobal
->VariableGlobal
,
1410 (UINTN
) &Variable
.CurrPtr
->State
,
1414 if (EFI_ERROR (Status
)) {
1418 } else if (Status
== EFI_NOT_FOUND
) {
1420 // Create a new variable
1424 // Make sure we are trying to create a new variable.
1425 // Setting a data variable with no access, or zero DataSize attributes means to delete it.
1427 if (DataSize
== 0 || (Attributes
& (EFI_VARIABLE_RUNTIME_ACCESS
| EFI_VARIABLE_BOOTSERVICE_ACCESS
)) == 0) {
1428 Status
= EFI_NOT_FOUND
;
1433 // Only variable have NV|RT attribute can be created in Runtime
1435 if (EfiAtRuntime () &&
1436 (!(Attributes
& EFI_VARIABLE_RUNTIME_ACCESS
) || !(Attributes
& EFI_VARIABLE_NON_VOLATILE
))) {
1437 Status
= EFI_INVALID_PARAMETER
;
1442 // Status should be EFI_INVALID_PARAMETER here according to return status of FindVariable().
1444 ASSERT (Status
== EFI_INVALID_PARAMETER
);
1449 // Function part - create a new variable and copy the data.
1450 // Both update a variable and create a variable will come here.
1452 // Tricky part: Use scratch data area at the end of volatile variable store
1453 // as a temporary storage.
1455 NextVariable
= GetEndPointer ((VARIABLE_STORE_HEADER
*) ((UINTN
) mVariableModuleGlobal
->VariableGlobal
.VolatileVariableBase
));
1457 SetMem (NextVariable
, SCRATCH_SIZE
, 0xff);
1459 NextVariable
->StartId
= VARIABLE_DATA
;
1460 NextVariable
->Attributes
= Attributes
;
1462 // NextVariable->State = VAR_ADDED;
1464 NextVariable
->Reserved
= 0;
1465 VarNameOffset
= sizeof (VARIABLE_HEADER
);
1466 VarNameSize
= StrSize (VariableName
);
1468 (UINT8
*) ((UINTN
) NextVariable
+ VarNameOffset
),
1472 VarDataOffset
= VarNameOffset
+ VarNameSize
+ GET_PAD_SIZE (VarNameSize
);
1474 (UINT8
*) ((UINTN
) NextVariable
+ VarDataOffset
),
1478 CopyMem (&NextVariable
->VendorGuid
, VendorGuid
, sizeof (EFI_GUID
));
1480 // There will be pad bytes after Data, the NextVariable->NameSize and
1481 // NextVariable->DataSize should not include pad size so that variable
1482 // service can get actual size in GetVariable
1484 NextVariable
->NameSize
= (UINT32
)VarNameSize
;
1485 NextVariable
->DataSize
= (UINT32
)DataSize
;
1488 // The actual size of the variable that stores in storage should
1489 // include pad size.
1491 VarSize
= VarDataOffset
+ DataSize
+ GET_PAD_SIZE (DataSize
);
1492 if (Attributes
& EFI_VARIABLE_NON_VOLATILE
) {
1494 // Create a nonvolatile variable
1498 if ((UINT32
) (VarSize
+*NonVolatileOffset
) >
1499 ((VARIABLE_STORE_HEADER
*) ((UINTN
) (mVariableModuleGlobal
->VariableGlobal
.NonVolatileVariableBase
)))->Size
1501 if (EfiAtRuntime ()) {
1502 Status
= EFI_OUT_OF_RESOURCES
;
1506 // Perform garbage collection & reclaim operation
1508 Status
= Reclaim (mVariableModuleGlobal
->VariableGlobal
.NonVolatileVariableBase
, NonVolatileOffset
, FALSE
, Variable
.CurrPtr
);
1509 if (EFI_ERROR (Status
)) {
1513 // If still no enough space, return out of resources
1515 if ((UINT32
) (VarSize
+*NonVolatileOffset
) >
1516 ((VARIABLE_STORE_HEADER
*) ((UINTN
) (mVariableModuleGlobal
->VariableGlobal
.NonVolatileVariableBase
)))->Size
1518 Status
= EFI_OUT_OF_RESOURCES
;
1526 // 1. Write variable header
1527 // 2. Set variable state to header valid
1528 // 3. Write variable data
1529 // 4. Set variable state to valid
1534 Status
= UpdateVariableStore (
1535 &mVariableModuleGlobal
->VariableGlobal
,
1540 sizeof (VARIABLE_HEADER
),
1541 (UINT8
*) NextVariable
1544 if (EFI_ERROR (Status
)) {
1551 NextVariable
->State
= VAR_HEADER_VALID_ONLY
;
1552 Status
= UpdateVariableStore (
1553 &mVariableModuleGlobal
->VariableGlobal
,
1558 sizeof (VARIABLE_HEADER
),
1559 (UINT8
*) NextVariable
1562 if (EFI_ERROR (Status
)) {
1568 Status
= UpdateVariableStore (
1569 &mVariableModuleGlobal
->VariableGlobal
,
1573 *NonVolatileOffset
+ sizeof (VARIABLE_HEADER
),
1574 (UINT32
) VarSize
- sizeof (VARIABLE_HEADER
),
1575 (UINT8
*) NextVariable
+ sizeof (VARIABLE_HEADER
)
1578 if (EFI_ERROR (Status
)) {
1584 NextVariable
->State
= VAR_ADDED
;
1585 Status
= UpdateVariableStore (
1586 &mVariableModuleGlobal
->VariableGlobal
,
1591 sizeof (VARIABLE_HEADER
),
1592 (UINT8
*) NextVariable
1595 if (EFI_ERROR (Status
)) {
1599 *NonVolatileOffset
= HEADER_ALIGN (*NonVolatileOffset
+ VarSize
);
1603 // Create a volatile variable
1607 if ((UINT32
) (VarSize
+*VolatileOffset
) >
1608 ((VARIABLE_STORE_HEADER
*) ((UINTN
) (mVariableModuleGlobal
->VariableGlobal
.VolatileVariableBase
)))->Size
) {
1610 // Perform garbage collection & reclaim operation
1612 Status
= Reclaim (mVariableModuleGlobal
->VariableGlobal
.VolatileVariableBase
, VolatileOffset
, TRUE
, Variable
.CurrPtr
);
1613 if (EFI_ERROR (Status
)) {
1617 // If still no enough space, return out of resources
1619 if ((UINT32
) (VarSize
+*VolatileOffset
) >
1620 ((VARIABLE_STORE_HEADER
*) ((UINTN
) (mVariableModuleGlobal
->VariableGlobal
.VolatileVariableBase
)))->Size
1622 Status
= EFI_OUT_OF_RESOURCES
;
1629 NextVariable
->State
= VAR_ADDED
;
1630 Status
= UpdateVariableStore (
1631 &mVariableModuleGlobal
->VariableGlobal
,
1637 (UINT8
*) NextVariable
1640 if (EFI_ERROR (Status
)) {
1644 *VolatileOffset
= HEADER_ALIGN (*VolatileOffset
+ VarSize
);
1647 // Mark the old variable as deleted
1649 if (!Reclaimed
&& !EFI_ERROR (Status
) && Variable
.CurrPtr
!= NULL
) {
1650 State
= Variable
.CurrPtr
->State
;
1651 State
&= VAR_DELETED
;
1653 Status
= UpdateVariableStore (
1654 &mVariableModuleGlobal
->VariableGlobal
,
1658 (UINTN
) &Variable
.CurrPtr
->State
,
1663 if (!EFI_ERROR (Status
)) {
1664 UpdateVariableInfo (VariableName
, VendorGuid
, Volatile
, FALSE
, TRUE
, FALSE
, FALSE
);
1665 UpdateVariableCache (VariableName
, VendorGuid
, Attributes
, DataSize
, Data
);
1670 Status
= EFI_SUCCESS
;
1671 UpdateVariableInfo (VariableName
, VendorGuid
, Volatile
, FALSE
, TRUE
, FALSE
, FALSE
);
1672 UpdateVariableCache (VariableName
, VendorGuid
, Attributes
, DataSize
, Data
);
1675 InterlockedDecrement (&mVariableModuleGlobal
->VariableGlobal
.ReentrantState
);
1676 ReleaseLockOnlyAtBootTime (&mVariableModuleGlobal
->VariableGlobal
.VariableServicesLock
);
1684 Routine Description:
1686 This code returns information about the EFI variables.
1690 Attributes Attributes bitmask to specify the type of variables
1691 on which to return information.
1692 MaximumVariableStorageSize Pointer to the maximum size of the storage space available
1693 for the EFI variables associated with the attributes specified.
1694 RemainingVariableStorageSize Pointer to the remaining size of the storage space available
1695 for EFI variables associated with the attributes specified.
1696 MaximumVariableSize Pointer to the maximum size of an individual EFI variables
1697 associated with the attributes specified.
1698 Global Pointer to VARIABLE_GLOBAL structure.
1699 Instance Instance of the Firmware Volume.
1704 EFI_INVALID_PARAMETER - An invalid combination of attribute bits was supplied.
1705 EFI_SUCCESS - Query successfully.
1706 EFI_UNSUPPORTED - The attribute is not supported on this platform.
1711 RuntimeServiceQueryVariableInfo (
1712 IN UINT32 Attributes
,
1713 OUT UINT64
*MaximumVariableStorageSize
,
1714 OUT UINT64
*RemainingVariableStorageSize
,
1715 OUT UINT64
*MaximumVariableSize
1718 VARIABLE_HEADER
*Variable
;
1719 VARIABLE_HEADER
*NextVariable
;
1720 UINT64 VariableSize
;
1721 VARIABLE_STORE_HEADER
*VariableStoreHeader
;
1723 if(MaximumVariableStorageSize
== NULL
|| RemainingVariableStorageSize
== NULL
|| MaximumVariableSize
== NULL
|| Attributes
== 0) {
1724 return EFI_INVALID_PARAMETER
;
1727 if((Attributes
& (EFI_VARIABLE_NON_VOLATILE
| EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_RUNTIME_ACCESS
| EFI_VARIABLE_HARDWARE_ERROR_RECORD
)) == 0) {
1729 // Make sure the Attributes combination is supported by the platform.
1731 return EFI_UNSUPPORTED
;
1732 } else if ((Attributes
& (EFI_VARIABLE_RUNTIME_ACCESS
| EFI_VARIABLE_BOOTSERVICE_ACCESS
)) == EFI_VARIABLE_RUNTIME_ACCESS
) {
1734 // Make sure if runtime bit is set, boot service bit is set also.
1736 return EFI_INVALID_PARAMETER
;
1737 } else if (EfiAtRuntime () && !(Attributes
& EFI_VARIABLE_RUNTIME_ACCESS
)) {
1739 // Make sure RT Attribute is set if we are in Runtime phase.
1741 return EFI_INVALID_PARAMETER
;
1744 AcquireLockOnlyAtBootTime(&mVariableModuleGlobal
->VariableGlobal
.VariableServicesLock
);
1746 if((Attributes
& EFI_VARIABLE_NON_VOLATILE
) == 0) {
1748 // Query is Volatile related.
1750 VariableStoreHeader
= (VARIABLE_STORE_HEADER
*) ((UINTN
) mVariableModuleGlobal
->VariableGlobal
.VolatileVariableBase
);
1753 // Query is Non-Volatile related.
1755 VariableStoreHeader
= (VARIABLE_STORE_HEADER
*) ((UINTN
) mVariableModuleGlobal
->VariableGlobal
.NonVolatileVariableBase
);
1759 // Now let's fill *MaximumVariableStorageSize *RemainingVariableStorageSize
1760 // with the storage size (excluding the storage header size).
1762 *MaximumVariableStorageSize
= VariableStoreHeader
->Size
- sizeof (VARIABLE_STORE_HEADER
);
1763 *RemainingVariableStorageSize
= VariableStoreHeader
->Size
- sizeof (VARIABLE_STORE_HEADER
);
1766 // Let *MaximumVariableSize be MAX_VARIABLE_SIZE with the exception of the variable header size.
1768 *MaximumVariableSize
= MAX_VARIABLE_SIZE
- sizeof (VARIABLE_HEADER
);
1771 // Harware error record variable needs larger size.
1773 if ((Attributes
& EFI_VARIABLE_HARDWARE_ERROR_RECORD
) == EFI_VARIABLE_HARDWARE_ERROR_RECORD
) {
1774 *MaximumVariableSize
= MAX_HARDWARE_ERROR_VARIABLE_SIZE
- sizeof (VARIABLE_HEADER
);
1778 // Point to the starting address of the variables.
1780 Variable
= GetStartPointer (VariableStoreHeader
);
1783 // Now walk through the related variable store.
1785 while (IsValidVariableHeader (Variable
) && (Variable
< GetEndPointer (VariableStoreHeader
))) {
1786 NextVariable
= GetNextVariablePtr (Variable
);
1787 VariableSize
= (UINT64
) (UINTN
) NextVariable
- (UINT64
) (UINTN
) Variable
;
1789 if (EfiAtRuntime ()) {
1791 // we don't take the state of the variables in mind
1792 // when calculating RemainingVariableStorageSize,
1793 // since the space occupied by variables not marked with
1794 // VAR_ADDED is not allowed to be reclaimed in Runtime.
1796 *RemainingVariableStorageSize
-= VariableSize
;
1799 // Only care about Variables with State VAR_ADDED,because
1800 // the space not marked as VAR_ADDED is reclaimable now.
1802 if (Variable
->State
== VAR_ADDED
) {
1803 *RemainingVariableStorageSize
-= VariableSize
;
1808 // Go to the next one
1810 Variable
= NextVariable
;
1813 if (*RemainingVariableStorageSize
< sizeof (VARIABLE_HEADER
)) {
1814 *MaximumVariableSize
= 0;
1815 } else if ((*RemainingVariableStorageSize
- sizeof (VARIABLE_HEADER
)) < *MaximumVariableSize
) {
1816 *MaximumVariableSize
= *RemainingVariableStorageSize
- sizeof (VARIABLE_HEADER
);
1819 ReleaseLockOnlyAtBootTime (&mVariableModuleGlobal
->VariableGlobal
.VariableServicesLock
);
1833 VarSize
= ((VARIABLE_STORE_HEADER
*) ((UINTN
) mVariableModuleGlobal
->VariableGlobal
.NonVolatileVariableBase
))->Size
;
1834 Status
= EFI_SUCCESS
;
1837 // Check if the free area is blow a threshold
1839 if ((VarSize
- mVariableModuleGlobal
->NonVolatileLastVariableOffset
) < VARIABLE_RECLAIM_THRESHOLD
) {
1841 mVariableModuleGlobal
->VariableGlobal
.NonVolatileVariableBase
,
1842 &mVariableModuleGlobal
->NonVolatileLastVariableOffset
,
1846 ASSERT_EFI_ERROR (Status
);
1851 VariableCommonInitialize (
1852 IN EFI_HANDLE ImageHandle
,
1853 IN EFI_SYSTEM_TABLE
*SystemTable
1857 Routine Description:
1858 This function does common initialization for variable services
1862 ImageHandle - The firmware allocated handle for the EFI image.
1863 SystemTable - A pointer to the EFI System Table.
1869 EFI_NOT_FOUND - Variable store area not found.
1870 EFI_UNSUPPORTED - Currently only one non-volatile variable store is supported.
1871 EFI_SUCCESS - Variable services successfully initialized.
1876 EFI_FIRMWARE_VOLUME_HEADER
*FwVolHeader
;
1878 VARIABLE_STORE_HEADER
*VolatileVariableStore
;
1879 VARIABLE_STORE_HEADER
*VariableStoreHeader
;
1880 VARIABLE_HEADER
*NextVariable
;
1882 EFI_PHYSICAL_ADDRESS FvVolHdr
;
1883 UINT64 TempVariableStoreHeader
;
1884 EFI_GCD_MEMORY_SPACE_DESCRIPTOR GcdDescriptor
;
1889 UINT64 VariableStoreBase
;
1890 UINT64 VariableStoreLength
;
1891 EFI_EVENT ReadyToBootEvent
;
1893 Status
= EFI_SUCCESS
;
1895 // Allocate runtime memory for variable driver global structure.
1897 mVariableModuleGlobal
= AllocateRuntimePool (sizeof (VARIABLE_MODULE_GLOBAL
));
1898 if (mVariableModuleGlobal
== NULL
) {
1899 return EFI_OUT_OF_RESOURCES
;
1902 EfiInitializeLock(&mVariableModuleGlobal
->VariableGlobal
.VariableServicesLock
, TPL_NOTIFY
);
1903 mVariableModuleGlobal
->VariableGlobal
.ReentrantState
= 0;
1906 // Allocate memory for volatile variable store
1908 VolatileVariableStore
= AllocateRuntimePool (VARIABLE_STORE_SIZE
+ SCRATCH_SIZE
);
1909 if (VolatileVariableStore
== NULL
) {
1910 FreePool (mVariableModuleGlobal
);
1911 return EFI_OUT_OF_RESOURCES
;
1914 SetMem (VolatileVariableStore
, VARIABLE_STORE_SIZE
+ SCRATCH_SIZE
, 0xff);
1917 // Variable Specific Data
1919 mVariableModuleGlobal
->VariableGlobal
.VolatileVariableBase
= (EFI_PHYSICAL_ADDRESS
) (UINTN
) VolatileVariableStore
;
1920 mVariableModuleGlobal
->VolatileLastVariableOffset
= (UINTN
) GetStartPointer (VolatileVariableStore
) - (UINTN
) VolatileVariableStore
;
1922 VolatileVariableStore
->Signature
= VARIABLE_STORE_SIGNATURE
;
1923 VolatileVariableStore
->Size
= VARIABLE_STORE_SIZE
;
1924 VolatileVariableStore
->Format
= VARIABLE_STORE_FORMATTED
;
1925 VolatileVariableStore
->State
= VARIABLE_STORE_HEALTHY
;
1926 VolatileVariableStore
->Reserved
= 0;
1927 VolatileVariableStore
->Reserved1
= 0;
1930 // Get non volatile varaible store
1933 TempVariableStoreHeader
= (UINT64
) PcdGet32 (PcdFlashNvStorageVariableBase
);
1934 VariableStoreBase
= TempVariableStoreHeader
+ \
1935 (((EFI_FIRMWARE_VOLUME_HEADER
*) (UINTN
) (TempVariableStoreHeader
)) -> HeaderLength
);
1936 VariableStoreLength
= (UINT64
) PcdGet32 (PcdFlashNvStorageVariableSize
) - \
1937 (((EFI_FIRMWARE_VOLUME_HEADER
*) (UINTN
) (TempVariableStoreHeader
)) -> HeaderLength
);
1939 // Mark the variable storage region of the FLASH as RUNTIME
1941 BaseAddress
= VariableStoreBase
& (~EFI_PAGE_MASK
);
1942 Length
= VariableStoreLength
+ (VariableStoreBase
- BaseAddress
);
1943 Length
= (Length
+ EFI_PAGE_SIZE
- 1) & (~EFI_PAGE_MASK
);
1945 Status
= gDS
->GetMemorySpaceDescriptor (BaseAddress
, &GcdDescriptor
);
1946 if (EFI_ERROR (Status
)) {
1950 Status
= gDS
->SetMemorySpaceAttributes (
1953 GcdDescriptor
.Attributes
| EFI_MEMORY_RUNTIME
1955 if (EFI_ERROR (Status
)) {
1959 // Get address of non volatile variable store base
1961 mVariableModuleGlobal
->VariableGlobal
.NonVolatileVariableBase
= VariableStoreBase
;
1967 // Find the Correct Instance of the FV Block Service.
1970 CurrPtr
= (CHAR8
*) ((UINTN
) mVariableModuleGlobal
->VariableGlobal
.NonVolatileVariableBase
);
1971 while (EfiFvbGetPhysicalAddress (Instance
, &FvVolHdr
) == EFI_SUCCESS
) {
1972 FwVolHeader
= (EFI_FIRMWARE_VOLUME_HEADER
*) ((UINTN
) FvVolHdr
);
1973 if (CurrPtr
>= (CHAR8
*) FwVolHeader
&& CurrPtr
< (((CHAR8
*) FwVolHeader
) + FwVolHeader
->FvLength
)) {
1974 mVariableModuleGlobal
->FvbInstance
= Instance
;
1981 VariableStoreHeader
= (VARIABLE_STORE_HEADER
*) CurrPtr
;
1982 if (GetVariableStoreStatus (VariableStoreHeader
) == EfiValid
) {
1983 if (~VariableStoreHeader
->Size
== 0) {
1984 Status
= UpdateVariableStore (
1985 &mVariableModuleGlobal
->VariableGlobal
,
1988 mVariableModuleGlobal
->FvbInstance
,
1989 (UINTN
) &VariableStoreHeader
->Size
,
1991 (UINT8
*) &VariableStoreLength
1994 // As Variables are stored in NV storage, which are slow devices,such as flash.
1995 // Variable operation may skip checking variable program result to improve performance,
1996 // We can assume Variable program is OK through some check point.
1997 // Variable Store Size Setting should be the first Variable write operation,
1998 // We can assume all Read/Write is OK if we can set Variable store size successfully.
1999 // If write fail, we will assert here
2001 ASSERT(VariableStoreHeader
->Size
== VariableStoreLength
);
2003 if (EFI_ERROR (Status
)) {
2008 mVariableModuleGlobal
->VariableGlobal
.NonVolatileVariableBase
= (EFI_PHYSICAL_ADDRESS
) ((UINTN
) CurrPtr
);
2010 // Parse non-volatile variable data and get last variable offset
2012 NextVariable
= GetStartPointer ((VARIABLE_STORE_HEADER
*) CurrPtr
);
2013 Status
= EFI_SUCCESS
;
2015 while (IsValidVariableHeader (NextVariable
)) {
2016 NextVariable
= GetNextVariablePtr (NextVariable
);
2019 mVariableModuleGlobal
->NonVolatileLastVariableOffset
= (UINTN
) NextVariable
- (UINTN
) CurrPtr
;
2022 // Check if the free area is really free.
2024 for (Index
= mVariableModuleGlobal
->NonVolatileLastVariableOffset
; Index
< VariableStoreHeader
->Size
; Index
++) {
2025 Data
= ((UINT8
*) (UINTN
) mVariableModuleGlobal
->VariableGlobal
.NonVolatileVariableBase
)[Index
];
2028 // There must be something wrong in variable store, do reclaim operation.
2031 mVariableModuleGlobal
->VariableGlobal
.NonVolatileVariableBase
,
2032 &mVariableModuleGlobal
->NonVolatileLastVariableOffset
,
2037 if (EFI_ERROR (Status
)) {
2046 // Register the event handling function to reclaim variable for OS usage.
2048 Status
= EfiCreateEventReadyToBootEx (
2057 if (EFI_ERROR (Status
)) {
2058 FreePool (mVariableModuleGlobal
);
2059 FreePool (VolatileVariableStore
);
2067 VariableClassAddressChangeEvent (
2074 (VOID
**) &mVariableModuleGlobal
->VariableGlobal
.NonVolatileVariableBase
2078 (VOID
**) &mVariableModuleGlobal
->VariableGlobal
.VolatileVariableBase
2080 EfiConvertPointer (0x0, (VOID
**) &mVariableModuleGlobal
);
2085 Variable Driver main entry point. The Variable driver places the 4 EFI
2086 runtime services in the EFI System Table and installs arch protocols
2087 for variable read and write services being availible.
2089 @param[in] ImageHandle The firmware allocated handle for the EFI image.
2090 @param[in] SystemTable A pointer to the EFI System Table.
2092 @retval EFI_SUCCESS The entry point is executed successfully.
2093 @retval other Some error occurs when executing this entry point.
2098 VariableServiceInitialize (
2099 IN EFI_HANDLE ImageHandle
,
2100 IN EFI_SYSTEM_TABLE
*SystemTable
2105 Status
= VariableCommonInitialize (ImageHandle
, SystemTable
);
2106 ASSERT_EFI_ERROR (Status
);
2108 SystemTable
->RuntimeServices
->GetVariable
= RuntimeServiceGetVariable
;
2109 SystemTable
->RuntimeServices
->GetNextVariableName
= RuntimeServiceGetNextVariableName
;
2110 SystemTable
->RuntimeServices
->SetVariable
= RuntimeServiceSetVariable
;
2111 SystemTable
->RuntimeServices
->QueryVariableInfo
= RuntimeServiceQueryVariableInfo
;
2114 // Now install the Variable Runtime Architectural Protocol on a new handle
2116 Status
= gBS
->InstallMultipleProtocolInterfaces (
2118 &gEfiVariableArchProtocolGuid
, NULL
,
2119 &gEfiVariableWriteArchProtocolGuid
, NULL
,
2122 ASSERT_EFI_ERROR (Status
);
2124 Status
= gBS
->CreateEvent (
2125 EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE
,
2127 VariableClassAddressChangeEvent
,
2129 &mVirtualAddressChangeEvent
2131 ASSERT_EFI_ERROR (Status
);