3 Copyright (c) 2006 - 2007, Intel Corporation
4 All rights reserved. This program and the accompanying materials
5 are licensed and made available under the terms and conditions of the BSD License
6 which accompanies this distribution. The full text of the license may be found at
7 http://opensource.org/licenses/bsd-license.php
9 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
10 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
18 Provide support functions for variable services.
22 #include "FSVariable.h"
24 VARIABLE_STORE_HEADER mStoreHeaderTemplate
= {
25 VARIABLE_STORE_SIGNATURE
,
26 VOLATILE_VARIABLE_STORE_SIZE
,
27 VARIABLE_STORE_FORMATTED
,
28 VARIABLE_STORE_HEALTHY
,
34 // Don't use module globals after the SetVirtualAddress map is signaled
36 VARIABLE_GLOBAL
*mGlobal
;
41 OnVirtualAddressChange (
49 OnSimpleFileSystemInstall (
56 IsValidVariableHeader (
57 IN VARIABLE_HEADER
*Variable
63 This code checks if variable header is valid or not.
66 Variable Pointer to the Variable Header.
69 TRUE Variable header is valid.
70 FALSE Variable header is not valid.
74 if (Variable
== NULL
||
75 Variable
->StartId
!= VARIABLE_DATA
||
76 (sizeof (VARIABLE_HEADER
) + Variable
->NameSize
+ Variable
->DataSize
) > MAX_VARIABLE_SIZE
86 GetVariableStoreStatus (
87 IN VARIABLE_STORE_HEADER
*VarStoreHeader
93 This code gets the current status of Variable Store.
97 VarStoreHeader Pointer to the Variable Store Header.
101 EfiRaw Variable store status is raw
102 EfiValid Variable store status is valid
103 EfiInvalid Variable store status is invalid
107 if ((VarStoreHeader
->Signature
== mStoreHeaderTemplate
.Signature
) &&
108 (VarStoreHeader
->Format
== mStoreHeaderTemplate
.Format
) &&
109 (VarStoreHeader
->State
== mStoreHeaderTemplate
.State
)
112 } else if (VarStoreHeader
->Signature
== VAR_DEFAULT_VALUE_32
&&
113 VarStoreHeader
->Size
== VAR_DEFAULT_VALUE_32
&&
114 VarStoreHeader
->Format
== VAR_DEFAULT_VALUE
&&
115 VarStoreHeader
->State
== VAR_DEFAULT_VALUE
127 IN VARIABLE_HEADER
*Variable
133 This code gets the pointer to the variable data.
137 Variable Pointer to the Variable Header.
141 UINT8* Pointer to Variable Data
146 // Be careful about pad size for alignment
148 return (UINT8
*) ((UINTN
) GET_VARIABLE_NAME_PTR (Variable
) + Variable
->NameSize
+ GET_PAD_SIZE (Variable
->NameSize
));
154 IN VARIABLE_HEADER
*Variable
160 This code gets the pointer to the next variable header.
164 Variable Pointer to the Variable Header.
168 VARIABLE_HEADER* Pointer to next variable header.
172 if (!IsValidVariableHeader (Variable
)) {
176 // Be careful about pad size for alignment
178 return (VARIABLE_HEADER
*) ((UINTN
) GetVariableDataPtr (Variable
) + Variable
->DataSize
+ GET_PAD_SIZE (Variable
->DataSize
));
184 IN VARIABLE_STORE_HEADER
*VarStoreHeader
190 This code gets the pointer to the last variable memory pointer byte
194 VarStoreHeader Pointer to the Variable Store Header.
198 VARIABLE_HEADER* Pointer to last unavailable Variable Header
203 // The end of variable store
205 return (VARIABLE_HEADER
*) ((UINTN
) VarStoreHeader
+ VarStoreHeader
->Size
);
210 IN VARIABLE_HEADER
*Variable
216 Check if exist newer variable when doing reclaim
220 Variable Pointer to start position
224 TRUE - Exists another variable, which is newer than the current one
225 FALSE - Doesn't exist another vairable which is newer than the current one
229 VARIABLE_HEADER
*NextVariable
;
230 CHAR16
*VariableName
;
231 EFI_GUID
*VendorGuid
;
233 VendorGuid
= &Variable
->VendorGuid
;
234 VariableName
= GET_VARIABLE_NAME_PTR(Variable
);
236 NextVariable
= GetNextVariablePtr (Variable
);
237 while (IsValidVariableHeader (NextVariable
)) {
238 if ((NextVariable
->State
== VAR_ADDED
) || (NextVariable
->State
== (VAR_ADDED
& VAR_IN_DELETED_TRANSITION
))) {
240 // If match Guid and Name
242 if (CompareGuid (VendorGuid
, &NextVariable
->VendorGuid
)) {
243 if (CompareMem (VariableName
, GET_VARIABLE_NAME_PTR (NextVariable
), StrSize (VariableName
)) == 0) {
248 NextVariable
= GetNextVariablePtr (NextVariable
);
256 IN VARIABLE_STORAGE_TYPE StorageType
,
257 IN VARIABLE_HEADER
*CurrentVariable OPTIONAL
263 Variable store garbage collection and reclaim operation
267 IsVolatile The variable store is volatile or not,
268 if it is non-volatile, need FTW
269 CurrentVairable If it is not NULL, it means not to process
270 current variable for Reclaim.
278 VARIABLE_HEADER
*Variable
;
279 VARIABLE_HEADER
*NextVariable
;
280 VARIABLE_STORE_HEADER
*VariableStoreHeader
;
282 UINTN ValidBufferSize
;
287 VariableStoreHeader
= (VARIABLE_STORE_HEADER
*) mGlobal
->VariableBase
[StorageType
];
290 // Start Pointers for the variable.
292 Variable
= (VARIABLE_HEADER
*) (VariableStoreHeader
+ 1);
296 // To make the reclaim, here we just allocate a memory that equal to the original memory
298 ValidBufferSize
= sizeof (VARIABLE_STORE_HEADER
) + VariableStoreHeader
->Size
;
300 Status
= gBS
->AllocatePool (
305 if (EFI_ERROR (Status
)) {
309 CurrPtr
= ValidBuffer
;
312 // Copy variable store header
314 CopyMem (CurrPtr
, VariableStoreHeader
, sizeof (VARIABLE_STORE_HEADER
));
315 CurrPtr
+= sizeof (VARIABLE_STORE_HEADER
);
318 // Start Pointers for the variable.
320 Variable
= (VARIABLE_HEADER
*) (VariableStoreHeader
+ 1);
323 ValidBufferSize
= sizeof (VARIABLE_STORE_HEADER
);
324 while (IsValidVariableHeader (Variable
)) {
325 NextVariable
= GetNextVariablePtr (Variable
);
327 // State VAR_ADDED or VAR_IN_DELETED_TRANSITION are to kept,
328 // The CurrentVariable, is also saved, as SetVariable may fail due to lack of space
330 if (Variable
->State
== VAR_ADDED
) {
331 VariableSize
= (UINTN
) NextVariable
- (UINTN
) Variable
;
332 CopyMem (CurrPtr
, (UINT8
*) Variable
, VariableSize
);
333 ValidBufferSize
+= VariableSize
;
334 CurrPtr
+= VariableSize
;
335 } else if (Variable
->State
== (VAR_ADDED
& VAR_IN_DELETED_TRANSITION
)) {
337 // As variables that with the same guid and name may exist in NV due to power failure during SetVariable,
338 // we will only save the latest valid one
340 if (!ExistNewerVariable(Variable
)) {
341 VariableSize
= (UINTN
) NextVariable
- (UINTN
) Variable
;
342 CopyMem (CurrPtr
, (UINT8
*) Variable
, VariableSize
);
344 // If CurrentVariable == Variable, mark as VAR_IN_DELETED_TRANSITION
346 if (Variable
!= CurrentVariable
){
347 ((VARIABLE_HEADER
*)CurrPtr
)->State
= VAR_ADDED
;
349 CurrPtr
+= VariableSize
;
350 ValidBufferSize
+= VariableSize
;
353 Variable
= NextVariable
;
357 // TODO: cannot restore to original state, basic FTW needed
359 Status
= mGlobal
->VariableStore
[StorageType
]->Erase (
360 mGlobal
->VariableStore
[StorageType
]
362 Status
= mGlobal
->VariableStore
[StorageType
]->Write (
363 mGlobal
->VariableStore
[StorageType
],
369 // ASSERT_EFI_ERROR (Status);
371 mGlobal
->LastVariableOffset
[StorageType
] = ValidBufferSize
;
372 gBS
->FreePool (ValidBuffer
);
380 IN CHAR16
*VariableName
,
381 IN EFI_GUID
*VendorGuid
,
382 OUT VARIABLE_POINTER_TRACK
*PtrTrack
388 This code finds variable in storage blocks (Volatile or Non-Volatile)
392 VariableName Name of the variable to be found
393 VendorGuid Vendor GUID to be found.
394 PtrTrack Variable Track Pointer structure that contains
395 Variable Information.
396 Contains the pointer of Variable header.
400 EFI_INVALID_PARAMETER - Invalid parameter
401 EFI_SUCCESS - Find the specified variable
402 EFI_NOT_FOUND - Not found
406 VARIABLE_HEADER
*Variable
;
407 VARIABLE_STORE_HEADER
*VariableStoreHeader
;
409 VARIABLE_HEADER
*InDeleteVariable
;
411 VARIABLE_HEADER
*InDeleteStartPtr
;
412 VARIABLE_HEADER
*InDeleteEndPtr
;
414 if (VariableName
[0] != 0 && VendorGuid
== NULL
) {
415 return EFI_INVALID_PARAMETER
;
418 InDeleteVariable
= NULL
;
419 InDeleteIndex
= (UINTN
)-1;
420 InDeleteStartPtr
= NULL
;
421 InDeleteEndPtr
= NULL
;
423 for (Index
= 0; Index
< MaxType
; Index
++) {
425 // 0: Non-Volatile, 1: Volatile
427 VariableStoreHeader
= (VARIABLE_STORE_HEADER
*) mGlobal
->VariableBase
[Index
];
430 // Start Pointers for the variable.
431 // Actual Data Pointer where data can be written.
433 Variable
= (VARIABLE_HEADER
*) (VariableStoreHeader
+ 1);
436 // Find the variable by walk through non-volatile and volatile variable store
438 PtrTrack
->StartPtr
= Variable
;
439 PtrTrack
->EndPtr
= GetEndPointer (VariableStoreHeader
);
441 while (IsValidVariableHeader (Variable
) && (Variable
< PtrTrack
->EndPtr
)) {
442 if (Variable
->State
== VAR_ADDED
) {
443 if (!EfiAtRuntime () || (Variable
->Attributes
& EFI_VARIABLE_RUNTIME_ACCESS
)) {
444 if (VariableName
[0] == 0) {
445 PtrTrack
->CurrPtr
= Variable
;
446 PtrTrack
->Type
= (VARIABLE_STORAGE_TYPE
) Index
;
449 if (CompareGuid (VendorGuid
, &Variable
->VendorGuid
)) {
450 if (!CompareMem (VariableName
, GET_VARIABLE_NAME_PTR (Variable
), StrSize (VariableName
))) {
451 PtrTrack
->CurrPtr
= Variable
;
452 PtrTrack
->Type
= (VARIABLE_STORAGE_TYPE
) Index
;
458 } else if (Variable
->State
== (VAR_ADDED
& VAR_IN_DELETED_TRANSITION
)) {
460 // VAR_IN_DELETED_TRANSITION should also be checked.
462 if (!EfiAtRuntime () || (Variable
->Attributes
& EFI_VARIABLE_RUNTIME_ACCESS
)) {
463 if (VariableName
[0] == 0) {
464 InDeleteVariable
= Variable
;
465 InDeleteIndex
= Index
;
466 InDeleteStartPtr
= PtrTrack
->StartPtr
;
467 InDeleteEndPtr
= PtrTrack
->EndPtr
;
469 if (CompareGuid (VendorGuid
, &Variable
->VendorGuid
)) {
470 if (!CompareMem (VariableName
, GET_VARIABLE_NAME_PTR (Variable
), StrSize (VariableName
))) {
471 InDeleteVariable
= Variable
;
472 InDeleteIndex
= Index
;
473 InDeleteStartPtr
= PtrTrack
->StartPtr
;
474 InDeleteEndPtr
= PtrTrack
->EndPtr
;
481 Variable
= GetNextVariablePtr (Variable
);
492 // if VAR_IN_DELETED_TRANSITION found, and VAR_ADDED not found,
495 if (InDeleteVariable
!= NULL
) {
496 PtrTrack
->CurrPtr
= InDeleteVariable
;
497 PtrTrack
->Type
= (VARIABLE_STORAGE_TYPE
) InDeleteIndex
;
498 PtrTrack
->StartPtr
= InDeleteStartPtr
;
499 PtrTrack
->EndPtr
= InDeleteEndPtr
;
503 PtrTrack
->CurrPtr
= NULL
;
504 return EFI_NOT_FOUND
;
510 IN CHAR16
*VariableName
,
511 IN EFI_GUID
*VendorGuid
,
512 OUT UINT32
*Attributes OPTIONAL
,
513 IN OUT UINTN
*DataSize
,
520 This code finds variable in storage blocks (Volatile or Non-Volatile)
524 VariableName Name of Variable to be found
525 VendorGuid Variable vendor GUID
526 Attributes OPTIONAL Attribute value of the variable found
527 DataSize Size of Data found. If size is less than the
528 data, this value contains the required size.
537 VARIABLE_POINTER_TRACK Variable
;
541 if (VariableName
== NULL
|| VendorGuid
== NULL
|| DataSize
== NULL
) {
542 return EFI_INVALID_PARAMETER
;
546 // Find existing variable
548 Status
= FindVariable (VariableName
, VendorGuid
, &Variable
);
550 if (Variable
.CurrPtr
== NULL
|| EFI_ERROR (Status
)) {
556 VarDataSize
= Variable
.CurrPtr
->DataSize
;
557 if (*DataSize
>= VarDataSize
) {
559 return EFI_INVALID_PARAMETER
;
561 CopyMem (Data
, GetVariableDataPtr (Variable
.CurrPtr
), VarDataSize
);
563 if (Attributes
!= NULL
) {
564 *Attributes
= Variable
.CurrPtr
->Attributes
;
567 *DataSize
= VarDataSize
;
571 *DataSize
= VarDataSize
;
572 return EFI_BUFFER_TOO_SMALL
;
578 GetNextVariableName (
579 IN OUT UINTN
*VariableNameSize
,
580 IN OUT CHAR16
*VariableName
,
581 IN OUT EFI_GUID
*VendorGuid
587 This code Finds the Next available variable
591 VariableNameSize Size of the variable
592 VariableName Pointer to variable name
593 VendorGuid Variable Vendor Guid
601 VARIABLE_POINTER_TRACK Variable
;
605 if (VariableNameSize
== NULL
|| VariableName
== NULL
|| VendorGuid
== NULL
) {
606 return EFI_INVALID_PARAMETER
;
609 Status
= FindVariable (VariableName
, VendorGuid
, &Variable
);
611 if (Variable
.CurrPtr
== NULL
|| EFI_ERROR (Status
)) {
615 if (VariableName
[0] != 0) {
617 // If variable name is not NULL, get next variable
619 Variable
.CurrPtr
= GetNextVariablePtr (Variable
.CurrPtr
);
624 // The order we find variable is: 1). NonVolatile; 2). Volatile
625 // If both volatile and non-volatile variable store are parsed,
628 if (Variable
.CurrPtr
>= Variable
.EndPtr
|| Variable
.CurrPtr
== NULL
) {
629 if (Variable
.Type
== Volatile
) {
631 // Since we met the end of Volatile storage, we have parsed all the stores.
633 return EFI_NOT_FOUND
;
637 // End of NonVolatile, continue to parse Volatile
639 Variable
.Type
= Volatile
;
640 Variable
.StartPtr
= (VARIABLE_HEADER
*) ((VARIABLE_STORE_HEADER
*) mGlobal
->VariableBase
[Volatile
] + 1);
641 Variable
.EndPtr
= (VARIABLE_HEADER
*) GetEndPointer ((VARIABLE_STORE_HEADER
*) mGlobal
->VariableBase
[Volatile
]);
643 Variable
.CurrPtr
= Variable
.StartPtr
;
644 if (!IsValidVariableHeader (Variable
.CurrPtr
)) {
651 if (IsValidVariableHeader (Variable
.CurrPtr
) &&
652 ((Variable
.CurrPtr
->State
== VAR_ADDED
) ||
653 (Variable
.CurrPtr
->State
== (VAR_ADDED
& VAR_IN_DELETED_TRANSITION
)))) {
654 if (!EfiAtRuntime () || (Variable
.CurrPtr
->Attributes
& EFI_VARIABLE_RUNTIME_ACCESS
)) {
655 VarNameSize
= Variable
.CurrPtr
->NameSize
;
656 if (VarNameSize
<= *VariableNameSize
) {
659 GET_VARIABLE_NAME_PTR (Variable
.CurrPtr
),
664 &Variable
.CurrPtr
->VendorGuid
,
667 Status
= EFI_SUCCESS
;
669 Status
= EFI_BUFFER_TOO_SMALL
;
672 *VariableNameSize
= VarNameSize
;
677 Variable
.CurrPtr
= GetNextVariablePtr (Variable
.CurrPtr
);
680 return EFI_NOT_FOUND
;
686 IN CHAR16
*VariableName
,
687 IN EFI_GUID
*VendorGuid
,
688 IN UINT32 Attributes
,
696 This code sets variable in storage blocks (Volatile or Non-Volatile)
700 VariableName Name of Variable to be found
701 VendorGuid Variable vendor GUID
702 Attributes Attribute value of the variable found
703 DataSize Size of Data found. If size is less than the
704 data, this value contains the required size.
709 EFI_INVALID_PARAMETER - Invalid parameter
710 EFI_SUCCESS - Set successfully
711 EFI_OUT_OF_RESOURCES - Resource not enough to set variable
712 EFI_NOT_FOUND - Not found
713 EFI_DEVICE_ERROR - Variable can not be saved due to hardware failure
714 EFI_WRITE_PROTECTED - Variable is read-only
718 VARIABLE_POINTER_TRACK Variable
;
720 VARIABLE_HEADER
*NextVariable
;
727 VARIABLE_STORAGE_TYPE StorageType
;
732 // Check input parameters
735 if (VariableName
== NULL
|| VariableName
[0] == 0 || VendorGuid
== NULL
) {
736 return EFI_INVALID_PARAMETER
;
740 // Make sure if runtime bit is set, boot service bit is set also
742 if ((Attributes
& (EFI_VARIABLE_RUNTIME_ACCESS
| EFI_VARIABLE_BOOTSERVICE_ACCESS
)) == EFI_VARIABLE_RUNTIME_ACCESS
) {
743 return EFI_INVALID_PARAMETER
;
746 #if (EFI_SPECIFICATION_VERSION >= 0x0002000A)
748 // The size of the VariableName, including the Unicode Null in bytes plus
749 // the DataSize is limited to maximum size of MAX_HARDWARE_ERROR_VARIABLE_SIZE (32K)
750 // bytes for HwErrRec, and MAX_VARIABLE_SIZE (1024) bytes for the others.
752 if ((Attributes
& EFI_VARIABLE_HARDWARE_ERROR_RECORD
) == EFI_VARIABLE_HARDWARE_ERROR_RECORD
) {
753 if ((DataSize
> MAX_HARDWARE_ERROR_VARIABLE_SIZE
) ||
754 (sizeof (VARIABLE_HEADER
) + StrSize (VariableName
) + DataSize
> MAX_HARDWARE_ERROR_VARIABLE_SIZE
)) {
755 return EFI_INVALID_PARAMETER
;
758 if ((DataSize
> MAX_VARIABLE_SIZE
) ||
759 (sizeof (VARIABLE_HEADER
) + StrSize (VariableName
) + DataSize
> MAX_VARIABLE_SIZE
)) {
760 return EFI_INVALID_PARAMETER
;
765 // The size of the VariableName, including the Unicode Null in bytes plus
766 // the DataSize is limited to maximum size of MAX_VARIABLE_SIZE (1024) bytes.
768 if ((DataSize
> MAX_VARIABLE_SIZE
) ||
769 (sizeof (VARIABLE_HEADER
) + StrSize (VariableName
) + DataSize
> MAX_VARIABLE_SIZE
)) {
770 return EFI_INVALID_PARAMETER
;
774 // Check whether the input variable is already existed
777 Status
= FindVariable (VariableName
, VendorGuid
, &Variable
);
779 if (Status
== EFI_SUCCESS
&& Variable
.CurrPtr
!= NULL
) {
781 // Update/Delete existing variable
784 if (EfiAtRuntime ()) {
786 // If EfiAtRuntime and the variable is Volatile and Runtime Access,
787 // the volatile is ReadOnly, and SetVariable should be aborted and
788 // return EFI_WRITE_PROTECTED.
790 if (Variable
.Type
== Volatile
) {
791 return EFI_WRITE_PROTECTED
;
794 // Only variable have NV attribute can be updated/deleted in Runtime
796 if (!(Variable
.CurrPtr
->Attributes
& EFI_VARIABLE_NON_VOLATILE
)) {
797 return EFI_INVALID_PARAMETER
;
802 // Setting a data variable with no access, or zero DataSize attributes
803 // specified causes it to be deleted.
805 if (DataSize
== 0 || (Attributes
& (EFI_VARIABLE_RUNTIME_ACCESS
| EFI_VARIABLE_BOOTSERVICE_ACCESS
)) == 0) {
807 // Found this variable in storage
809 State
= Variable
.CurrPtr
->State
;
810 State
&= VAR_DELETED
;
812 Status
= mGlobal
->VariableStore
[Variable
.Type
]->Write (
813 mGlobal
->VariableStore
[Variable
.Type
],
814 VARIABLE_MEMBER_OFFSET (State
, (UINTN
) Variable
.CurrPtr
- (UINTN
) Variable
.StartPtr
),
815 sizeof (Variable
.CurrPtr
->State
),
819 // NOTE: Write operation at least can write data to memory cache
820 // Discard file writing failure here.
826 // Found this variable in storage
827 // If the variable is marked valid and the same data has been passed in
828 // then return to the caller immediately.
830 if ((Variable
.CurrPtr
->DataSize
== DataSize
) &&
831 (CompareMem (Data
, GetVariableDataPtr (Variable
.CurrPtr
), DataSize
) == 0)
834 } else if ((Variable
.CurrPtr
->State
== VAR_ADDED
) ||
835 (Variable
.CurrPtr
->State
== (VAR_ADDED
& VAR_IN_DELETED_TRANSITION
))) {
837 // Mark the old variable as in delete transition
839 State
= Variable
.CurrPtr
->State
;
840 State
&= VAR_IN_DELETED_TRANSITION
;
842 Status
= mGlobal
->VariableStore
[Variable
.Type
]->Write (
843 mGlobal
->VariableStore
[Variable
.Type
],
844 VARIABLE_MEMBER_OFFSET (State
, (UINTN
) Variable
.CurrPtr
- (UINTN
) Variable
.StartPtr
),
845 sizeof (Variable
.CurrPtr
->State
),
849 // NOTE: Write operation at least can write data to memory cache
850 // Discard file writing failure here.
853 } else if (Status
== EFI_NOT_FOUND
) {
855 // Create a new variable
859 // Make sure we are trying to create a new variable.
860 // Setting a data variable with no access, or zero DataSize attributes means to delete it.
862 if (DataSize
== 0 || (Attributes
& (EFI_VARIABLE_RUNTIME_ACCESS
| EFI_VARIABLE_BOOTSERVICE_ACCESS
)) == 0) {
863 return EFI_NOT_FOUND
;
866 // Only variable have NV|RT attribute can be created in Runtime
868 if (EfiAtRuntime () &&
869 (!(Attributes
& EFI_VARIABLE_RUNTIME_ACCESS
) || !(Attributes
& EFI_VARIABLE_NON_VOLATILE
))) {
870 return EFI_INVALID_PARAMETER
;
875 // Status should be EFI_INVALID_PARAMETER here according to return status of FindVariable().
881 // Function part - create a new variable and copy the data.
882 // Both update a variable and create a variable will come here.
883 // We can firstly write all the data in memory, then write them to file
884 // This can reduce the times of write operation
887 NextVariable
= (VARIABLE_HEADER
*) mGlobal
->Scratch
;
889 NextVariable
->StartId
= VARIABLE_DATA
;
890 NextVariable
->Attributes
= Attributes
;
891 NextVariable
->State
= VAR_ADDED
;
892 NextVariable
->Reserved
= 0;
893 VarNameOffset
= sizeof (VARIABLE_HEADER
);
894 VarNameSize
= StrSize (VariableName
);
896 (UINT8
*) ((UINTN
) NextVariable
+ VarNameOffset
),
900 VarDataOffset
= VarNameOffset
+ VarNameSize
+ GET_PAD_SIZE (VarNameSize
);
902 (UINT8
*) ((UINTN
) NextVariable
+ VarDataOffset
),
906 CopyMem (&NextVariable
->VendorGuid
, VendorGuid
, sizeof (EFI_GUID
));
908 // There will be pad bytes after Data, the NextVariable->NameSize and
909 // NextVariable->DataSize should not include pad size so that variable
910 // service can get actual size in GetVariable
912 NextVariable
->NameSize
= (UINT32
)VarNameSize
;
913 NextVariable
->DataSize
= (UINT32
)DataSize
;
916 // The actual size of the variable that stores in storage should
918 // VarDataOffset: offset from begin of current variable header
920 VarSize
= VarDataOffset
+ DataSize
+ GET_PAD_SIZE (DataSize
);
922 StorageType
= (Attributes
& EFI_VARIABLE_NON_VOLATILE
) ? NonVolatile
: Volatile
;
924 if ((UINT32
) (VarSize
+ mGlobal
->LastVariableOffset
[StorageType
]) >
925 ((VARIABLE_STORE_HEADER
*) mGlobal
->VariableBase
[StorageType
])->Size
927 if ((StorageType
== NonVolatile
) && EfiAtRuntime ()) {
928 return EFI_OUT_OF_RESOURCES
;
931 // Perform garbage collection & reclaim operation
933 Status
= Reclaim (StorageType
, Variable
.CurrPtr
);
934 if (EFI_ERROR (Status
)) {
937 // we cannot restore to original state, fetal error, report to user
939 DEBUG ((EFI_D_ERROR
, "FSVariable: Recalim error (fetal error) - %r\n", Status
));
943 // If still no enough space, return out of resources
945 if ((UINT32
) (VarSize
+ mGlobal
->LastVariableOffset
[StorageType
]) >
946 ((VARIABLE_STORE_HEADER
*) mGlobal
->VariableBase
[StorageType
])->Size
948 return EFI_OUT_OF_RESOURCES
;
953 Status
= mGlobal
->VariableStore
[StorageType
]->Write (
954 mGlobal
->VariableStore
[StorageType
],
955 mGlobal
->LastVariableOffset
[StorageType
],
960 // NOTE: Write operation at least can write data to memory cache
961 // Discard file writing failure here.
963 mGlobal
->LastVariableOffset
[StorageType
] += VarSize
;
966 // Mark the old variable as deleted
968 if (!Reclaimed
&& !EFI_ERROR (Status
) && Variable
.CurrPtr
!= NULL
) {
969 State
= Variable
.CurrPtr
->State
;
970 State
&= VAR_DELETED
;
972 Status
= mGlobal
->VariableStore
[StorageType
]->Write (
973 mGlobal
->VariableStore
[StorageType
],
974 VARIABLE_MEMBER_OFFSET (State
, (UINTN
) Variable
.CurrPtr
- (UINTN
) Variable
.StartPtr
),
975 sizeof (Variable
.CurrPtr
->State
),
979 // NOTE: Write operation at least can write data to memory cache
980 // Discard file writing failure here.
987 #if (EFI_SPECIFICATION_VERSION >= 0x00020000)
991 IN UINT32 Attributes
,
992 OUT UINT64
*MaximumVariableStorageSize
,
993 OUT UINT64
*RemainingVariableStorageSize
,
994 OUT UINT64
*MaximumVariableSize
1000 This code returns information about the EFI variables.
1004 Attributes Attributes bitmask to specify the type of variables
1005 on which to return information.
1006 MaximumVariableStorageSize Pointer to the maximum size of the storage space available
1007 for the EFI variables associated with the attributes specified.
1008 RemainingVariableStorageSize Pointer to the remaining size of the storage space available
1009 for the EFI variables associated with the attributes specified.
1010 MaximumVariableSize Pointer to the maximum size of the individual EFI variables
1011 associated with the attributes specified.
1016 EFI_INVALID_PARAMETER - An invalid combination of attribute bits was supplied.
1017 EFI_SUCCESS - Query successfully.
1018 EFI_UNSUPPORTED - The attribute is not supported on this platform.
1022 VARIABLE_HEADER
*Variable
;
1023 VARIABLE_HEADER
*NextVariable
;
1024 UINT64 VariableSize
;
1025 VARIABLE_STORE_HEADER
*VariableStoreHeader
;
1027 if(MaximumVariableStorageSize
== NULL
|| RemainingVariableStorageSize
== NULL
|| MaximumVariableSize
== NULL
|| Attributes
== 0) {
1028 return EFI_INVALID_PARAMETER
;
1031 #if (EFI_SPECIFICATION_VERSION >= 0x0002000A)
1032 if((Attributes
& (EFI_VARIABLE_NON_VOLATILE
| EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_RUNTIME_ACCESS
| EFI_VARIABLE_HARDWARE_ERROR_RECORD
)) == 0) {
1034 // Make sure the Attributes combination is supported by the platform.
1036 return EFI_UNSUPPORTED
;
1039 if((Attributes
& (EFI_VARIABLE_NON_VOLATILE
| EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_RUNTIME_ACCESS
)) == 0) {
1041 // Make sure the Attributes combination is supported by the platform.
1043 return EFI_UNSUPPORTED
;
1046 else if ((Attributes
& (EFI_VARIABLE_RUNTIME_ACCESS
| EFI_VARIABLE_BOOTSERVICE_ACCESS
)) == EFI_VARIABLE_RUNTIME_ACCESS
) {
1048 // Make sure if runtime bit is set, boot service bit is set also.
1050 return EFI_INVALID_PARAMETER
;
1051 } else if (EfiAtRuntime () && !(Attributes
& EFI_VARIABLE_RUNTIME_ACCESS
)) {
1053 // Make sure RT Attribute is set if we are in Runtime phase.
1055 return EFI_INVALID_PARAMETER
;
1058 VariableStoreHeader
= (VARIABLE_STORE_HEADER
*) mGlobal
->VariableBase
[
1059 (Attributes
& EFI_VARIABLE_NON_VOLATILE
) ? NonVolatile
: Volatile
1062 // Now let's fill *MaximumVariableStorageSize *RemainingVariableStorageSize
1063 // with the storage size (excluding the storage header size).
1065 *MaximumVariableStorageSize
= VariableStoreHeader
->Size
- sizeof (VARIABLE_STORE_HEADER
);
1066 *RemainingVariableStorageSize
= VariableStoreHeader
->Size
- sizeof (VARIABLE_STORE_HEADER
);
1069 // Let *MaximumVariableSize be MAX_VARIABLE_SIZE with the exception of the variable header size.
1071 *MaximumVariableSize
= MAX_VARIABLE_SIZE
- sizeof (VARIABLE_HEADER
);
1073 #if (EFI_SPECIFICATION_VERSION >= 0x0002000A)
1075 // Harware error record variable needs larger size.
1077 if ((Attributes
& EFI_VARIABLE_HARDWARE_ERROR_RECORD
) == EFI_VARIABLE_HARDWARE_ERROR_RECORD
) {
1078 *MaximumVariableSize
= MAX_HARDWARE_ERROR_VARIABLE_SIZE
- sizeof (VARIABLE_HEADER
);
1083 // Point to the starting address of the variables.
1085 Variable
= (VARIABLE_HEADER
*) (VariableStoreHeader
+ 1);
1088 // Now walk through the related variable store.
1090 while (IsValidVariableHeader (Variable
) && (Variable
< GetEndPointer (VariableStoreHeader
))) {
1091 NextVariable
= GetNextVariablePtr (Variable
);
1092 VariableSize
= (UINT64
) (UINTN
) NextVariable
- (UINT64
) (UINTN
) Variable
;
1094 if (EfiAtRuntime ()) {
1096 // we don't take the state of the variables in mind
1097 // when calculating RemainingVariableStorageSize,
1098 // since the space occupied by variables not marked with
1099 // VAR_ADDED is not allowed to be reclaimed in Runtime.
1101 *RemainingVariableStorageSize
-= VariableSize
;
1104 // Only care about Variables with State VAR_ADDED,because
1105 // the space not marked as VAR_ADDED is reclaimable now.
1107 if ((Variable
->State
== VAR_ADDED
) ||
1108 (Variable
->State
== (VAR_ADDED
& VAR_IN_DELETED_TRANSITION
))) {
1109 *RemainingVariableStorageSize
-= VariableSize
;
1114 // Go to the next one
1116 Variable
= NextVariable
;
1119 if (*RemainingVariableStorageSize
< sizeof (VARIABLE_HEADER
)) {
1120 *MaximumVariableSize
= 0;
1121 } else if ((*RemainingVariableStorageSize
- sizeof (VARIABLE_HEADER
)) < *MaximumVariableSize
) {
1122 *MaximumVariableSize
= *RemainingVariableStorageSize
- sizeof (VARIABLE_HEADER
);
1131 VariableServiceInitialize (
1132 IN EFI_HANDLE ImageHandle
,
1133 IN EFI_SYSTEM_TABLE
*SystemTable
1137 Routine Description:
1138 This function does initialization for variable services
1142 ImageHandle - The firmware allocated handle for the EFI image.
1143 SystemTable - A pointer to the EFI System Table.
1149 EFI_NOT_FOUND - Variable store area not found.
1150 EFI_SUCCESS - Variable services successfully initialized.
1155 EFI_HANDLE NewHandle
;
1157 EFI_PEI_HOB_POINTERS GuidHob
;
1158 VARIABLE_HEADER
*NextVariable
;
1159 VARIABLE_STORE_HEADER
*VariableStoreHeader
;
1160 EFI_FLASH_MAP_FS_ENTRY_DATA
*FlashMapEntryData
;
1161 EFI_FLASH_SUBAREA_ENTRY VariableStoreEntry
;
1164 EFI_GCD_MEMORY_SPACE_DESCRIPTOR GcdDescriptor
;
1166 Status
= gBS
->AllocatePool (
1167 EfiRuntimeServicesData
,
1168 (UINTN
) sizeof (VARIABLE_GLOBAL
),
1171 if (EFI_ERROR (Status
)) {
1175 GuidHob
.Raw
= GetHobList ();
1176 FlashMapEntryData
= NULL
;
1177 while ((GuidHob
.Raw
= GetNextGuidHob (&gEfiFlashMapHobGuid
, GuidHob
.Raw
)) != NULL
) {
1178 FlashMapEntryData
= (EFI_FLASH_MAP_FS_ENTRY_DATA
*) GET_GUID_HOB_DATA (GuidHob
.Guid
);
1179 if (FlashMapEntryData
->AreaType
== EFI_FLASH_AREA_EFI_VARIABLES
) {
1182 GuidHob
.Raw
= GET_NEXT_HOB (GuidHob
);
1185 if (FlashMapEntryData
== NULL
) {
1186 DEBUG ((EFI_D_ERROR
, "FSVariable: Could not find flash area for variable!\n"));
1187 Status
= EFI_NOT_FOUND
;
1191 VariableStoreEntry
= FlashMapEntryData
->Entries
[0];
1194 // Mark the variable storage region of the FLASH as RUNTIME
1196 BaseAddress
= VariableStoreEntry
.Base
& (~EFI_PAGE_MASK
);
1197 Length
= VariableStoreEntry
.Length
+ (VariableStoreEntry
.Base
- BaseAddress
);
1198 Length
= (Length
+ EFI_PAGE_SIZE
- 1) & (~EFI_PAGE_MASK
);
1199 Status
= gDS
->GetMemorySpaceDescriptor (BaseAddress
, &GcdDescriptor
);
1200 if (EFI_ERROR (Status
)) {
1201 Status
= EFI_UNSUPPORTED
;
1204 Status
= gDS
->SetMemorySpaceAttributes (
1207 GcdDescriptor
.Attributes
| EFI_MEMORY_RUNTIME
1209 if (EFI_ERROR (Status
)) {
1210 Status
= EFI_UNSUPPORTED
;
1214 Status
= FileStorageConstructor (
1215 &mGlobal
->VariableStore
[NonVolatile
],
1216 &mGlobal
->GoVirtualChildEvent
[NonVolatile
],
1217 VariableStoreEntry
.Base
,
1218 (UINT32
) VariableStoreEntry
.Length
,
1219 FlashMapEntryData
->VolumeId
,
1220 FlashMapEntryData
->FilePath
1222 ASSERT_EFI_ERROR (Status
);
1227 Status
= MemStorageConstructor (
1228 &mGlobal
->VariableStore
[Volatile
],
1229 &mGlobal
->GoVirtualChildEvent
[Volatile
],
1230 VOLATILE_VARIABLE_STORE_SIZE
1232 ASSERT_EFI_ERROR (Status
);
1237 Status
= gBS
->AllocatePool (
1238 EfiRuntimeServicesData
,
1239 VARIABLE_SCRATCH_SIZE
,
1242 ASSERT_EFI_ERROR (Status
);
1247 Dev
= DEV_FROM_THIS (mGlobal
->VariableStore
[NonVolatile
]);
1248 VariableStoreHeader
= (VARIABLE_STORE_HEADER
*) VAR_DATA_PTR (Dev
);
1249 if (GetVariableStoreStatus (VariableStoreHeader
) == EfiValid
) {
1250 if (~VariableStoreHeader
->Size
== 0) {
1251 VariableStoreHeader
->Size
= (UINT32
) VariableStoreEntry
.Length
;
1255 // Calculate LastVariableOffset
1257 NextVariable
= (VARIABLE_HEADER
*) (VariableStoreHeader
+ 1);
1258 while (IsValidVariableHeader (NextVariable
)) {
1259 NextVariable
= GetNextVariablePtr (NextVariable
);
1261 mGlobal
->LastVariableOffset
[NonVolatile
] = (UINTN
) NextVariable
- (UINTN
) VariableStoreHeader
;
1262 mGlobal
->VariableBase
[NonVolatile
] = VariableStoreHeader
;
1265 // Reclaim if remaining space is too small
1267 if ((VariableStoreHeader
->Size
- mGlobal
->LastVariableOffset
[NonVolatile
]) < VARIABLE_RECLAIM_THRESHOLD
) {
1268 Status
= Reclaim (NonVolatile
, NULL
);
1269 if (EFI_ERROR (Status
)) {
1272 // we cannot restore to original state
1274 DEBUG ((EFI_D_ERROR
, "FSVariable: Recalim error (fetal error) - %r\n", Status
));
1275 ASSERT_EFI_ERROR (Status
);
1280 // 2. Volatile Storage
1282 Dev
= DEV_FROM_THIS (mGlobal
->VariableStore
[Volatile
]);
1283 VariableStoreHeader
= (VARIABLE_STORE_HEADER
*) VAR_DATA_PTR (Dev
);
1284 mGlobal
->VariableBase
[Volatile
] = VAR_DATA_PTR (Dev
);
1285 mGlobal
->LastVariableOffset
[Volatile
] = sizeof (VARIABLE_STORE_HEADER
);
1287 // init store_header & body in memory.
1289 mGlobal
->VariableStore
[Volatile
]->Erase (mGlobal
->VariableStore
[Volatile
]);
1290 mGlobal
->VariableStore
[Volatile
]->Write (
1291 mGlobal
->VariableStore
[Volatile
],
1293 sizeof (VARIABLE_STORE_HEADER
),
1294 &mStoreHeaderTemplate
1298 SystemTable
->RuntimeServices
->GetVariable
= GetVariable
;
1299 SystemTable
->RuntimeServices
->GetNextVariableName
= GetNextVariableName
;
1300 SystemTable
->RuntimeServices
->SetVariable
= SetVariable
;
1302 #if (EFI_SPECIFICATION_VERSION >= 0x00020000)
1303 SystemTable
->RuntimeServices
->QueryVariableInfo
= QueryVariableInfo
;
1307 // Now install the Variable Runtime Architectural Protocol on a new handle
1310 Status
= gBS
->InstallMultipleProtocolInterfaces (
1312 &gEfiVariableArchProtocolGuid
,
1314 &gEfiVariableWriteArchProtocolGuid
,
1318 ASSERT_EFI_ERROR (Status
);
1323 // EfiShutdownRuntimeDriverLib ();
1332 OnVirtualAddressChange (
1339 for (Index
= 0; Index
< MaxType
; Index
++) {
1340 mGlobal
->GoVirtualChildEvent
[Index
] (Event
, mGlobal
->VariableStore
[Index
]);
1341 EfiConvertPointer (0, &mGlobal
->VariableStore
[Index
]);
1342 EfiConvertPointer (0, &mGlobal
->VariableBase
[Index
]);
1344 EfiConvertPointer (0, &mGlobal
->Scratch
);
1345 EfiConvertPointer (0, &mGlobal
);