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
;
747 // The size of the VariableName, including the Unicode Null in bytes plus
748 // the DataSize is limited to maximum size of MAX_HARDWARE_ERROR_VARIABLE_SIZE (32K)
749 // bytes for HwErrRec, and MAX_VARIABLE_SIZE (1024) bytes for the others.
751 if ((Attributes
& EFI_VARIABLE_HARDWARE_ERROR_RECORD
) == EFI_VARIABLE_HARDWARE_ERROR_RECORD
) {
752 if ((DataSize
> MAX_HARDWARE_ERROR_VARIABLE_SIZE
) ||
753 (sizeof (VARIABLE_HEADER
) + StrSize (VariableName
) + DataSize
> MAX_HARDWARE_ERROR_VARIABLE_SIZE
)) {
754 return EFI_INVALID_PARAMETER
;
757 if ((DataSize
> MAX_VARIABLE_SIZE
) ||
758 (sizeof (VARIABLE_HEADER
) + StrSize (VariableName
) + DataSize
> MAX_VARIABLE_SIZE
)) {
759 return EFI_INVALID_PARAMETER
;
764 // Check whether the input variable is already existed
767 Status
= FindVariable (VariableName
, VendorGuid
, &Variable
);
769 if (Status
== EFI_SUCCESS
&& Variable
.CurrPtr
!= NULL
) {
771 // Update/Delete existing variable
774 if (EfiAtRuntime ()) {
776 // If EfiAtRuntime and the variable is Volatile and Runtime Access,
777 // the volatile is ReadOnly, and SetVariable should be aborted and
778 // return EFI_WRITE_PROTECTED.
780 if (Variable
.Type
== Volatile
) {
781 return EFI_WRITE_PROTECTED
;
784 // Only variable have NV attribute can be updated/deleted in Runtime
786 if (!(Variable
.CurrPtr
->Attributes
& EFI_VARIABLE_NON_VOLATILE
)) {
787 return EFI_INVALID_PARAMETER
;
792 // Setting a data variable with no access, or zero DataSize attributes
793 // specified causes it to be deleted.
795 if (DataSize
== 0 || (Attributes
& (EFI_VARIABLE_RUNTIME_ACCESS
| EFI_VARIABLE_BOOTSERVICE_ACCESS
)) == 0) {
797 // Found this variable in storage
799 State
= Variable
.CurrPtr
->State
;
800 State
&= VAR_DELETED
;
802 Status
= mGlobal
->VariableStore
[Variable
.Type
]->Write (
803 mGlobal
->VariableStore
[Variable
.Type
],
804 VARIABLE_MEMBER_OFFSET (State
, (UINTN
) Variable
.CurrPtr
- (UINTN
) Variable
.StartPtr
),
805 sizeof (Variable
.CurrPtr
->State
),
809 // NOTE: Write operation at least can write data to memory cache
810 // Discard file writing failure here.
816 // Found this variable in storage
817 // If the variable is marked valid and the same data has been passed in
818 // then return to the caller immediately.
820 if ((Variable
.CurrPtr
->DataSize
== DataSize
) &&
821 (CompareMem (Data
, GetVariableDataPtr (Variable
.CurrPtr
), DataSize
) == 0)
824 } else if ((Variable
.CurrPtr
->State
== VAR_ADDED
) ||
825 (Variable
.CurrPtr
->State
== (VAR_ADDED
& VAR_IN_DELETED_TRANSITION
))) {
827 // Mark the old variable as in delete transition
829 State
= Variable
.CurrPtr
->State
;
830 State
&= VAR_IN_DELETED_TRANSITION
;
832 Status
= mGlobal
->VariableStore
[Variable
.Type
]->Write (
833 mGlobal
->VariableStore
[Variable
.Type
],
834 VARIABLE_MEMBER_OFFSET (State
, (UINTN
) Variable
.CurrPtr
- (UINTN
) Variable
.StartPtr
),
835 sizeof (Variable
.CurrPtr
->State
),
839 // NOTE: Write operation at least can write data to memory cache
840 // Discard file writing failure here.
843 } else if (Status
== EFI_NOT_FOUND
) {
845 // Create a new variable
849 // Make sure we are trying to create a new variable.
850 // Setting a data variable with no access, or zero DataSize attributes means to delete it.
852 if (DataSize
== 0 || (Attributes
& (EFI_VARIABLE_RUNTIME_ACCESS
| EFI_VARIABLE_BOOTSERVICE_ACCESS
)) == 0) {
853 return EFI_NOT_FOUND
;
856 // Only variable have NV|RT attribute can be created in Runtime
858 if (EfiAtRuntime () &&
859 (!(Attributes
& EFI_VARIABLE_RUNTIME_ACCESS
) || !(Attributes
& EFI_VARIABLE_NON_VOLATILE
))) {
860 return EFI_INVALID_PARAMETER
;
865 // Status should be EFI_INVALID_PARAMETER here according to return status of FindVariable().
871 // Function part - create a new variable and copy the data.
872 // Both update a variable and create a variable will come here.
873 // We can firstly write all the data in memory, then write them to file
874 // This can reduce the times of write operation
877 NextVariable
= (VARIABLE_HEADER
*) mGlobal
->Scratch
;
879 NextVariable
->StartId
= VARIABLE_DATA
;
880 NextVariable
->Attributes
= Attributes
;
881 NextVariable
->State
= VAR_ADDED
;
882 NextVariable
->Reserved
= 0;
883 VarNameOffset
= sizeof (VARIABLE_HEADER
);
884 VarNameSize
= StrSize (VariableName
);
886 (UINT8
*) ((UINTN
) NextVariable
+ VarNameOffset
),
890 VarDataOffset
= VarNameOffset
+ VarNameSize
+ GET_PAD_SIZE (VarNameSize
);
892 (UINT8
*) ((UINTN
) NextVariable
+ VarDataOffset
),
896 CopyMem (&NextVariable
->VendorGuid
, VendorGuid
, sizeof (EFI_GUID
));
898 // There will be pad bytes after Data, the NextVariable->NameSize and
899 // NextVariable->DataSize should not include pad size so that variable
900 // service can get actual size in GetVariable
902 NextVariable
->NameSize
= (UINT32
)VarNameSize
;
903 NextVariable
->DataSize
= (UINT32
)DataSize
;
906 // The actual size of the variable that stores in storage should
908 // VarDataOffset: offset from begin of current variable header
910 VarSize
= VarDataOffset
+ DataSize
+ GET_PAD_SIZE (DataSize
);
912 StorageType
= (Attributes
& EFI_VARIABLE_NON_VOLATILE
) ? NonVolatile
: Volatile
;
914 if ((UINT32
) (VarSize
+ mGlobal
->LastVariableOffset
[StorageType
]) >
915 ((VARIABLE_STORE_HEADER
*) mGlobal
->VariableBase
[StorageType
])->Size
917 if ((StorageType
== NonVolatile
) && EfiAtRuntime ()) {
918 return EFI_OUT_OF_RESOURCES
;
921 // Perform garbage collection & reclaim operation
923 Status
= Reclaim (StorageType
, Variable
.CurrPtr
);
924 if (EFI_ERROR (Status
)) {
927 // we cannot restore to original state, fetal error, report to user
929 DEBUG ((EFI_D_ERROR
, "FSVariable: Recalim error (fetal error) - %r\n", Status
));
933 // If still no enough space, return out of resources
935 if ((UINT32
) (VarSize
+ mGlobal
->LastVariableOffset
[StorageType
]) >
936 ((VARIABLE_STORE_HEADER
*) mGlobal
->VariableBase
[StorageType
])->Size
938 return EFI_OUT_OF_RESOURCES
;
943 Status
= mGlobal
->VariableStore
[StorageType
]->Write (
944 mGlobal
->VariableStore
[StorageType
],
945 mGlobal
->LastVariableOffset
[StorageType
],
950 // NOTE: Write operation at least can write data to memory cache
951 // Discard file writing failure here.
953 mGlobal
->LastVariableOffset
[StorageType
] += VarSize
;
956 // Mark the old variable as deleted
958 if (!Reclaimed
&& !EFI_ERROR (Status
) && Variable
.CurrPtr
!= NULL
) {
959 State
= Variable
.CurrPtr
->State
;
960 State
&= VAR_DELETED
;
962 Status
= mGlobal
->VariableStore
[StorageType
]->Write (
963 mGlobal
->VariableStore
[StorageType
],
964 VARIABLE_MEMBER_OFFSET (State
, (UINTN
) Variable
.CurrPtr
- (UINTN
) Variable
.StartPtr
),
965 sizeof (Variable
.CurrPtr
->State
),
969 // NOTE: Write operation at least can write data to memory cache
970 // Discard file writing failure here.
980 IN UINT32 Attributes
,
981 OUT UINT64
*MaximumVariableStorageSize
,
982 OUT UINT64
*RemainingVariableStorageSize
,
983 OUT UINT64
*MaximumVariableSize
989 This code returns information about the EFI variables.
993 Attributes Attributes bitmask to specify the type of variables
994 on which to return information.
995 MaximumVariableStorageSize Pointer to the maximum size of the storage space available
996 for the EFI variables associated with the attributes specified.
997 RemainingVariableStorageSize Pointer to the remaining size of the storage space available
998 for the EFI variables associated with the attributes specified.
999 MaximumVariableSize Pointer to the maximum size of the individual EFI variables
1000 associated with the attributes specified.
1005 EFI_INVALID_PARAMETER - An invalid combination of attribute bits was supplied.
1006 EFI_SUCCESS - Query successfully.
1007 EFI_UNSUPPORTED - The attribute is not supported on this platform.
1011 VARIABLE_HEADER
*Variable
;
1012 VARIABLE_HEADER
*NextVariable
;
1013 UINT64 VariableSize
;
1014 VARIABLE_STORE_HEADER
*VariableStoreHeader
;
1016 if(MaximumVariableStorageSize
== NULL
|| RemainingVariableStorageSize
== NULL
|| MaximumVariableSize
== NULL
|| Attributes
== 0) {
1017 return EFI_INVALID_PARAMETER
;
1020 if((Attributes
& (EFI_VARIABLE_NON_VOLATILE
| EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_RUNTIME_ACCESS
| EFI_VARIABLE_HARDWARE_ERROR_RECORD
)) == 0) {
1022 // Make sure the Attributes combination is supported by the platform.
1024 return EFI_UNSUPPORTED
;
1026 else if ((Attributes
& (EFI_VARIABLE_RUNTIME_ACCESS
| EFI_VARIABLE_BOOTSERVICE_ACCESS
)) == EFI_VARIABLE_RUNTIME_ACCESS
) {
1028 // Make sure if runtime bit is set, boot service bit is set also.
1030 return EFI_INVALID_PARAMETER
;
1031 } else if (EfiAtRuntime () && !(Attributes
& EFI_VARIABLE_RUNTIME_ACCESS
)) {
1033 // Make sure RT Attribute is set if we are in Runtime phase.
1035 return EFI_INVALID_PARAMETER
;
1038 VariableStoreHeader
= (VARIABLE_STORE_HEADER
*) mGlobal
->VariableBase
[
1039 (Attributes
& EFI_VARIABLE_NON_VOLATILE
) ? NonVolatile
: Volatile
1042 // Now let's fill *MaximumVariableStorageSize *RemainingVariableStorageSize
1043 // with the storage size (excluding the storage header size).
1045 *MaximumVariableStorageSize
= VariableStoreHeader
->Size
- sizeof (VARIABLE_STORE_HEADER
);
1046 *RemainingVariableStorageSize
= VariableStoreHeader
->Size
- sizeof (VARIABLE_STORE_HEADER
);
1049 // Let *MaximumVariableSize be MAX_VARIABLE_SIZE with the exception of the variable header size.
1051 *MaximumVariableSize
= MAX_VARIABLE_SIZE
- sizeof (VARIABLE_HEADER
);
1054 // Harware error record variable needs larger size.
1056 if ((Attributes
& EFI_VARIABLE_HARDWARE_ERROR_RECORD
) == EFI_VARIABLE_HARDWARE_ERROR_RECORD
) {
1057 *MaximumVariableSize
= MAX_HARDWARE_ERROR_VARIABLE_SIZE
- sizeof (VARIABLE_HEADER
);
1061 // Point to the starting address of the variables.
1063 Variable
= (VARIABLE_HEADER
*) (VariableStoreHeader
+ 1);
1066 // Now walk through the related variable store.
1068 while (IsValidVariableHeader (Variable
) && (Variable
< GetEndPointer (VariableStoreHeader
))) {
1069 NextVariable
= GetNextVariablePtr (Variable
);
1070 VariableSize
= (UINT64
) (UINTN
) NextVariable
- (UINT64
) (UINTN
) Variable
;
1072 if (EfiAtRuntime ()) {
1074 // we don't take the state of the variables in mind
1075 // when calculating RemainingVariableStorageSize,
1076 // since the space occupied by variables not marked with
1077 // VAR_ADDED is not allowed to be reclaimed in Runtime.
1079 *RemainingVariableStorageSize
-= VariableSize
;
1082 // Only care about Variables with State VAR_ADDED,because
1083 // the space not marked as VAR_ADDED is reclaimable now.
1085 if ((Variable
->State
== VAR_ADDED
) ||
1086 (Variable
->State
== (VAR_ADDED
& VAR_IN_DELETED_TRANSITION
))) {
1087 *RemainingVariableStorageSize
-= VariableSize
;
1092 // Go to the next one
1094 Variable
= NextVariable
;
1097 if (*RemainingVariableStorageSize
< sizeof (VARIABLE_HEADER
)) {
1098 *MaximumVariableSize
= 0;
1099 } else if ((*RemainingVariableStorageSize
- sizeof (VARIABLE_HEADER
)) < *MaximumVariableSize
) {
1100 *MaximumVariableSize
= *RemainingVariableStorageSize
- sizeof (VARIABLE_HEADER
);
1108 VariableServiceInitialize (
1109 IN EFI_HANDLE ImageHandle
,
1110 IN EFI_SYSTEM_TABLE
*SystemTable
1114 Routine Description:
1115 This function does initialization for variable services
1119 ImageHandle - The firmware allocated handle for the EFI image.
1120 SystemTable - A pointer to the EFI System Table.
1126 EFI_NOT_FOUND - Variable store area not found.
1127 EFI_SUCCESS - Variable services successfully initialized.
1132 EFI_HANDLE NewHandle
;
1134 EFI_PEI_HOB_POINTERS GuidHob
;
1135 VARIABLE_HEADER
*NextVariable
;
1136 VARIABLE_STORE_HEADER
*VariableStoreHeader
;
1137 EFI_FLASH_MAP_FS_ENTRY_DATA
*FlashMapEntryData
;
1138 EFI_FLASH_SUBAREA_ENTRY VariableStoreEntry
;
1141 EFI_GCD_MEMORY_SPACE_DESCRIPTOR GcdDescriptor
;
1143 Status
= gBS
->AllocatePool (
1144 EfiRuntimeServicesData
,
1145 (UINTN
) sizeof (VARIABLE_GLOBAL
),
1148 if (EFI_ERROR (Status
)) {
1152 GuidHob
.Raw
= GetHobList ();
1153 FlashMapEntryData
= NULL
;
1154 while ((GuidHob
.Raw
= GetNextGuidHob (&gEfiFlashMapHobGuid
, GuidHob
.Raw
)) != NULL
) {
1155 FlashMapEntryData
= (EFI_FLASH_MAP_FS_ENTRY_DATA
*) GET_GUID_HOB_DATA (GuidHob
.Guid
);
1156 if (FlashMapEntryData
->AreaType
== EFI_FLASH_AREA_EFI_VARIABLES
) {
1159 GuidHob
.Raw
= GET_NEXT_HOB (GuidHob
);
1162 if (FlashMapEntryData
== NULL
) {
1163 DEBUG ((EFI_D_ERROR
, "FSVariable: Could not find flash area for variable!\n"));
1164 Status
= EFI_NOT_FOUND
;
1169 (VOID
*)&VariableStoreEntry
,
1170 (VOID
*)&FlashMapEntryData
->Entries
[0],
1171 sizeof(EFI_FLASH_SUBAREA_ENTRY
)
1175 // Mark the variable storage region of the FLASH as RUNTIME
1177 BaseAddress
= VariableStoreEntry
.Base
& (~EFI_PAGE_MASK
);
1178 Length
= VariableStoreEntry
.Length
+ (VariableStoreEntry
.Base
- BaseAddress
);
1179 Length
= (Length
+ EFI_PAGE_SIZE
- 1) & (~EFI_PAGE_MASK
);
1180 Status
= gDS
->GetMemorySpaceDescriptor (BaseAddress
, &GcdDescriptor
);
1181 if (EFI_ERROR (Status
)) {
1182 Status
= EFI_UNSUPPORTED
;
1185 Status
= gDS
->SetMemorySpaceAttributes (
1188 GcdDescriptor
.Attributes
| EFI_MEMORY_RUNTIME
1190 if (EFI_ERROR (Status
)) {
1191 Status
= EFI_UNSUPPORTED
;
1195 Status
= FileStorageConstructor (
1196 &mGlobal
->VariableStore
[NonVolatile
],
1197 &mGlobal
->GoVirtualChildEvent
[NonVolatile
],
1198 VariableStoreEntry
.Base
,
1199 (UINT32
) VariableStoreEntry
.Length
,
1200 FlashMapEntryData
->VolumeId
,
1201 FlashMapEntryData
->FilePath
1203 ASSERT_EFI_ERROR (Status
);
1208 Status
= MemStorageConstructor (
1209 &mGlobal
->VariableStore
[Volatile
],
1210 &mGlobal
->GoVirtualChildEvent
[Volatile
],
1211 VOLATILE_VARIABLE_STORE_SIZE
1213 ASSERT_EFI_ERROR (Status
);
1218 Status
= gBS
->AllocatePool (
1219 EfiRuntimeServicesData
,
1220 VARIABLE_SCRATCH_SIZE
,
1223 ASSERT_EFI_ERROR (Status
);
1228 Dev
= DEV_FROM_THIS (mGlobal
->VariableStore
[NonVolatile
]);
1229 VariableStoreHeader
= (VARIABLE_STORE_HEADER
*) VAR_DATA_PTR (Dev
);
1230 if (GetVariableStoreStatus (VariableStoreHeader
) == EfiValid
) {
1231 if (~VariableStoreHeader
->Size
== 0) {
1232 VariableStoreHeader
->Size
= (UINT32
) VariableStoreEntry
.Length
;
1236 // Calculate LastVariableOffset
1238 NextVariable
= (VARIABLE_HEADER
*) (VariableStoreHeader
+ 1);
1239 while (IsValidVariableHeader (NextVariable
)) {
1240 NextVariable
= GetNextVariablePtr (NextVariable
);
1242 mGlobal
->LastVariableOffset
[NonVolatile
] = (UINTN
) NextVariable
- (UINTN
) VariableStoreHeader
;
1243 mGlobal
->VariableBase
[NonVolatile
] = VariableStoreHeader
;
1246 // Reclaim if remaining space is too small
1248 if ((VariableStoreHeader
->Size
- mGlobal
->LastVariableOffset
[NonVolatile
]) < VARIABLE_RECLAIM_THRESHOLD
) {
1249 Status
= Reclaim (NonVolatile
, NULL
);
1250 if (EFI_ERROR (Status
)) {
1253 // we cannot restore to original state
1255 DEBUG ((EFI_D_ERROR
, "FSVariable: Recalim error (fetal error) - %r\n", Status
));
1256 ASSERT_EFI_ERROR (Status
);
1261 // 2. Volatile Storage
1263 Dev
= DEV_FROM_THIS (mGlobal
->VariableStore
[Volatile
]);
1264 VariableStoreHeader
= (VARIABLE_STORE_HEADER
*) VAR_DATA_PTR (Dev
);
1265 mGlobal
->VariableBase
[Volatile
] = VAR_DATA_PTR (Dev
);
1266 mGlobal
->LastVariableOffset
[Volatile
] = sizeof (VARIABLE_STORE_HEADER
);
1268 // init store_header & body in memory.
1270 mGlobal
->VariableStore
[Volatile
]->Erase (mGlobal
->VariableStore
[Volatile
]);
1271 mGlobal
->VariableStore
[Volatile
]->Write (
1272 mGlobal
->VariableStore
[Volatile
],
1274 sizeof (VARIABLE_STORE_HEADER
),
1275 &mStoreHeaderTemplate
1279 SystemTable
->RuntimeServices
->GetVariable
= GetVariable
;
1280 SystemTable
->RuntimeServices
->GetNextVariableName
= GetNextVariableName
;
1281 SystemTable
->RuntimeServices
->SetVariable
= SetVariable
;
1283 SystemTable
->RuntimeServices
->QueryVariableInfo
= QueryVariableInfo
;
1286 // Now install the Variable Runtime Architectural Protocol on a new handle
1289 Status
= gBS
->InstallMultipleProtocolInterfaces (
1291 &gEfiVariableArchProtocolGuid
,
1293 &gEfiVariableWriteArchProtocolGuid
,
1297 ASSERT_EFI_ERROR (Status
);
1302 // EfiShutdownRuntimeDriverLib ();
1311 OnVirtualAddressChange (
1318 for (Index
= 0; Index
< MaxType
; Index
++) {
1319 mGlobal
->GoVirtualChildEvent
[Index
] (Event
, mGlobal
->VariableStore
[Index
]);
1320 EfiConvertPointer (0, &mGlobal
->VariableStore
[Index
]);
1321 EfiConvertPointer (0, &mGlobal
->VariableBase
[Index
]);
1323 EfiConvertPointer (0, &mGlobal
->Scratch
);
1324 EfiConvertPointer (0, &mGlobal
);