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.
24 #include <Guid/FlashMapHob.h>
27 // Don't use module globals after the SetVirtualAddress map is signaled
29 ESAL_VARIABLE_GLOBAL
*mVariableModuleGlobal
;
32 // This is a temperary function which will be removed
33 // when EfiAcquireLock in UefiLib can handle the
34 // the call in UEFI Runtimer driver in RT phase.
38 AcquireLockOnlyAtBootTime (
42 if (!EfiAtRuntime ()) {
43 EfiAcquireLock (Lock
);
48 // This is a temperary function which will be removed
49 // when EfiAcquireLock in UefiLib can handle the
50 // the call in UEFI Runtimer driver in RT phase.
54 ReleaseLockOnlyAtBootTime (
58 if (!EfiAtRuntime ()) {
59 EfiReleaseLock (Lock
);
66 IsValidVariableHeader (
67 IN VARIABLE_HEADER
*Variable
73 This code checks if variable header is valid or not.
76 Variable Pointer to the Variable Header.
79 TRUE Variable header is valid.
80 FALSE Variable header is not valid.
84 if (Variable
== NULL
||
85 Variable
->StartId
!= VARIABLE_DATA
||
86 (sizeof (VARIABLE_HEADER
) + Variable
->NameSize
+ Variable
->DataSize
) > MAX_VARIABLE_SIZE
98 IN VARIABLE_GLOBAL
*Global
,
100 IN BOOLEAN SetByIndex
,
102 IN UINTN DataPtrIndex
,
110 This function writes data to the FWH at the correct LBA even if the LBAs
115 Global - Pointer to VARAIBLE_GLOBAL structure
116 Volatile - If the Variable is Volatile or Non-Volatile
117 SetByIndex - TRUE: Target pointer is given as index
118 FALSE: Target pointer is absolute
119 Instance - Instance of FV Block services
120 DataPtrIndex - Pointer to the Data from the end of VARIABLE_STORE_HEADER
122 DataSize - Size of data to be written.
123 Buffer - Pointer to the buffer from which data is written
127 EFI_INVALID_PARAMETER - Parameters not valid
128 EFI_SUCCESS - Variable store successfully updated
132 EFI_FV_BLOCK_MAP_ENTRY
*PtrBlockMapEntry
;
140 EFI_FIRMWARE_VOLUME_HEADER
*FwVolHeader
;
141 VARIABLE_STORE_HEADER
*VolatileBase
;
142 EFI_PHYSICAL_ADDRESS FvVolHdr
;
143 EFI_PHYSICAL_ADDRESS DataPtr
;
147 DataPtr
= DataPtrIndex
;
150 // Check if the Data is Volatile
153 EfiFvbGetPhysicalAddress (Instance
, &FvVolHdr
);
154 FwVolHeader
= (EFI_FIRMWARE_VOLUME_HEADER
*) ((UINTN
) FvVolHdr
);
156 // Data Pointer should point to the actual Address where data is to be
160 DataPtr
+= Global
->NonVolatileVariableBase
;
163 if ((DataPtr
+ DataSize
) >= ((EFI_PHYSICAL_ADDRESS
) (UINTN
) ((UINT8
*) FwVolHeader
+ FwVolHeader
->FvLength
))) {
164 return EFI_INVALID_PARAMETER
;
168 // Data Pointer should point to the actual Address where data is to be
171 VolatileBase
= (VARIABLE_STORE_HEADER
*) ((UINTN
) Global
->VolatileVariableBase
);
173 DataPtr
+= Global
->VolatileVariableBase
;
176 if ((DataPtr
+ DataSize
) >= ((UINTN
) ((UINT8
*) VolatileBase
+ VolatileBase
->Size
))) {
177 return EFI_INVALID_PARAMETER
;
181 // If Volatile Variable just do a simple mem copy.
183 CopyMem ((UINT8
*)(UINTN
)DataPtr
, Buffer
, DataSize
);
188 // If we are here we are dealing with Non-Volatile Variables
190 LinearOffset
= (UINTN
) FwVolHeader
;
191 CurrWritePtr
= (UINTN
) DataPtr
;
192 CurrWriteSize
= DataSize
;
196 if (CurrWritePtr
< LinearOffset
) {
197 return EFI_INVALID_PARAMETER
;
200 for (PtrBlockMapEntry
= FwVolHeader
->BlockMap
; PtrBlockMapEntry
->NumBlocks
!= 0; PtrBlockMapEntry
++) {
201 for (BlockIndex2
= 0; BlockIndex2
< PtrBlockMapEntry
->NumBlocks
; BlockIndex2
++) {
203 // Check to see if the Variable Writes are spanning through multiple
206 if ((CurrWritePtr
>= LinearOffset
) && (CurrWritePtr
< LinearOffset
+ PtrBlockMapEntry
->Length
)) {
207 if ((CurrWritePtr
+ CurrWriteSize
) <= (LinearOffset
+ PtrBlockMapEntry
->Length
)) {
208 Status
= EfiFvbWriteBlock (
211 (UINTN
) (CurrWritePtr
- LinearOffset
),
217 Size
= (UINT32
) (LinearOffset
+ PtrBlockMapEntry
->Length
- CurrWritePtr
);
218 Status
= EfiFvbWriteBlock (
221 (UINTN
) (CurrWritePtr
- LinearOffset
),
225 if (EFI_ERROR (Status
)) {
229 CurrWritePtr
= LinearOffset
+ PtrBlockMapEntry
->Length
;
230 CurrBuffer
= CurrBuffer
+ Size
;
231 CurrWriteSize
= CurrWriteSize
- Size
;
235 LinearOffset
+= PtrBlockMapEntry
->Length
;
244 VARIABLE_STORE_STATUS
246 GetVariableStoreStatus (
247 IN VARIABLE_STORE_HEADER
*VarStoreHeader
253 This code gets the current status of Variable Store.
257 VarStoreHeader Pointer to the Variable Store Header.
261 EfiRaw Variable store status is raw
262 EfiValid Variable store status is valid
263 EfiInvalid Variable store status is invalid
267 if (VarStoreHeader
->Signature
== VARIABLE_STORE_SIGNATURE
&&
268 VarStoreHeader
->Format
== VARIABLE_STORE_FORMATTED
&&
269 VarStoreHeader
->State
== VARIABLE_STORE_HEALTHY
273 } else if (VarStoreHeader
->Signature
== 0xffffffff &&
274 VarStoreHeader
->Size
== 0xffffffff &&
275 VarStoreHeader
->Format
== 0xff &&
276 VarStoreHeader
->State
== 0xff
289 IN VARIABLE_HEADER
*Variable
295 This code gets the pointer to the variable data.
299 Variable Pointer to the Variable Header.
303 UINT8* Pointer to Variable Data
308 // Be careful about pad size for alignment
310 return (UINT8
*) ((UINTN
) GET_VARIABLE_NAME_PTR (Variable
) + Variable
->NameSize
+ GET_PAD_SIZE (Variable
->NameSize
));
316 IN VARIABLE_HEADER
*Variable
322 This code gets the pointer to the next variable header.
326 Variable Pointer to the Variable Header.
330 VARIABLE_HEADER* Pointer to next variable header.
334 if (!IsValidVariableHeader (Variable
)) {
338 // Be careful about pad size for alignment
340 return (VARIABLE_HEADER
*) ((UINTN
) GetVariableDataPtr (Variable
) + Variable
->DataSize
+ GET_PAD_SIZE (Variable
->DataSize
));
347 IN VARIABLE_STORE_HEADER
*VarStoreHeader
353 This code gets the pointer to the last variable memory pointer byte
357 VarStoreHeader Pointer to the Variable Store Header.
361 VARIABLE_HEADER* Pointer to last unavailable Variable Header
366 // The end of variable store
368 return (VARIABLE_HEADER
*) ((UINTN
) VarStoreHeader
+ VarStoreHeader
->Size
);
375 IN EFI_PHYSICAL_ADDRESS VariableBase
,
376 OUT UINTN
*LastVariableOffset
,
377 IN BOOLEAN IsVolatile
383 Variable store garbage collection and reclaim operation
387 VariableBase Base address of variable store
388 LastVariableOffset Offset of last variable
389 IsVolatile The variable store is volatile or not,
390 if it is non-volatile, need FTW
398 VARIABLE_HEADER
*Variable
;
399 VARIABLE_HEADER
*NextVariable
;
400 VARIABLE_STORE_HEADER
*VariableStoreHeader
;
402 UINTN ValidBufferSize
;
407 VariableStoreHeader
= (VARIABLE_STORE_HEADER
*) ((UINTN
) VariableBase
);
410 // Start Pointers for the variable.
412 Variable
= (VARIABLE_HEADER
*) (VariableStoreHeader
+ 1);
414 ValidBufferSize
= sizeof (VARIABLE_STORE_HEADER
);
416 while (IsValidVariableHeader (Variable
)) {
417 NextVariable
= GetNextVariablePtr (Variable
);
418 if (Variable
->State
== VAR_ADDED
) {
419 VariableSize
= (UINTN
) NextVariable
- (UINTN
) Variable
;
420 ValidBufferSize
+= VariableSize
;
423 Variable
= NextVariable
;
426 ValidBuffer
= AllocatePool (ValidBufferSize
);
427 if (ValidBuffer
== NULL
) {
428 return EFI_OUT_OF_RESOURCES
;
431 SetMem (ValidBuffer
, ValidBufferSize
, 0xff);
433 CurrPtr
= ValidBuffer
;
436 // Copy variable store header
438 CopyMem (CurrPtr
, VariableStoreHeader
, sizeof (VARIABLE_STORE_HEADER
));
439 CurrPtr
+= sizeof (VARIABLE_STORE_HEADER
);
442 // Start Pointers for the variable.
444 Variable
= (VARIABLE_HEADER
*) (VariableStoreHeader
+ 1);
446 while (IsValidVariableHeader (Variable
)) {
447 NextVariable
= GetNextVariablePtr (Variable
);
448 if (Variable
->State
== VAR_ADDED
) {
449 VariableSize
= (UINTN
) NextVariable
- (UINTN
) Variable
;
450 CopyMem (CurrPtr
, (UINT8
*) Variable
, VariableSize
);
451 CurrPtr
+= VariableSize
;
454 Variable
= NextVariable
;
459 // If volatile variable store, just copy valid buffer
461 SetMem ((UINT8
*) (UINTN
) VariableBase
, VariableStoreHeader
->Size
, 0xff);
462 CopyMem ((UINT8
*) (UINTN
) VariableBase
, ValidBuffer
, ValidBufferSize
);
463 *LastVariableOffset
= ValidBufferSize
;
464 Status
= EFI_SUCCESS
;
467 // If non-volatile variable store, perform FTW here.
469 Status
= FtwVariableSpace (
474 if (!EFI_ERROR (Status
)) {
475 *LastVariableOffset
= ValidBufferSize
;
479 FreePool (ValidBuffer
);
481 if (EFI_ERROR (Status
)) {
482 *LastVariableOffset
= 0;
492 IN CHAR16
*VariableName
,
493 IN EFI_GUID
*VendorGuid
,
494 OUT VARIABLE_POINTER_TRACK
*PtrTrack
,
495 IN VARIABLE_GLOBAL
*Global
501 This code finds variable in storage blocks (Volatile or Non-Volatile)
505 VariableName Name of the variable to be found
506 VendorGuid Vendor GUID to be found.
507 PtrTrack Variable Track Pointer structure that contains
508 Variable Information.
509 Contains the pointer of Variable header.
510 Global VARIABLE_GLOBAL pointer
518 VARIABLE_HEADER
*Variable
[2];
519 VARIABLE_STORE_HEADER
*VariableStoreHeader
[2];
523 // We aquire the lock at the entry of FindVariable as GetVariable, GetNextVariableName
524 // SetVariable all call FindVariable at entry point. Please move "Aquire Lock" to
525 // the correct places if this assumption does not hold TRUE anymore.
527 AcquireLockOnlyAtBootTime(&Global
->VariableServicesLock
);
530 // 0: Non-Volatile, 1: Volatile
532 VariableStoreHeader
[0] = (VARIABLE_STORE_HEADER
*) ((UINTN
) Global
->NonVolatileVariableBase
);
533 VariableStoreHeader
[1] = (VARIABLE_STORE_HEADER
*) ((UINTN
) Global
->VolatileVariableBase
);
536 // Start Pointers for the variable.
537 // Actual Data Pointer where data can be written.
539 Variable
[0] = (VARIABLE_HEADER
*) (VariableStoreHeader
[0] + 1);
540 Variable
[1] = (VARIABLE_HEADER
*) (VariableStoreHeader
[1] + 1);
542 if (VariableName
[0] != 0 && VendorGuid
== NULL
) {
543 return EFI_INVALID_PARAMETER
;
546 // Find the variable by walk through non-volatile and volatile variable store
548 for (Index
= 0; Index
< 2; Index
++) {
549 PtrTrack
->StartPtr
= (VARIABLE_HEADER
*) (VariableStoreHeader
[Index
] + 1);
550 PtrTrack
->EndPtr
= GetEndPointer (VariableStoreHeader
[Index
]);
552 while (IsValidVariableHeader (Variable
[Index
]) && (Variable
[Index
] <= GetEndPointer (VariableStoreHeader
[Index
]))) {
553 if (Variable
[Index
]->State
== VAR_ADDED
) {
554 if (!EfiAtRuntime () || (Variable
[Index
]->Attributes
& EFI_VARIABLE_RUNTIME_ACCESS
)) {
555 if (VariableName
[0] == 0) {
556 PtrTrack
->CurrPtr
= Variable
[Index
];
557 PtrTrack
->Volatile
= (BOOLEAN
) Index
;
560 if (CompareGuid (VendorGuid
, &Variable
[Index
]->VendorGuid
)) {
561 if (!CompareMem (VariableName
, GET_VARIABLE_NAME_PTR (Variable
[Index
]), Variable
[Index
]->NameSize
)) {
562 PtrTrack
->CurrPtr
= Variable
[Index
];
563 PtrTrack
->Volatile
= (BOOLEAN
) Index
;
571 Variable
[Index
] = GetNextVariablePtr (Variable
[Index
]);
580 PtrTrack
->CurrPtr
= NULL
;
581 return EFI_NOT_FOUND
;
587 IN CHAR16
*VariableName
,
588 IN EFI_GUID
*VendorGuid
,
589 OUT UINT32
*Attributes OPTIONAL
,
590 IN OUT UINTN
*DataSize
,
592 IN VARIABLE_GLOBAL
*Global
,
599 This code finds variable in storage blocks (Volatile or Non-Volatile)
603 VariableName Name of Variable to be found
604 VendorGuid Variable vendor GUID
605 Attributes OPTIONAL Attribute value of the variable found
606 DataSize Size of Data found. If size is less than the
607 data, this value contains the required size.
609 Global Pointer to VARIABLE_GLOBAL structure
610 Instance Instance of the Firmware Volume.
614 EFI_INVALID_PARAMETER - Invalid parameter
615 EFI_SUCCESS - Find the specified variable
616 EFI_NOT_FOUND - Not found
617 EFI_BUFFER_TO_SMALL - DataSize is too small for the result
622 VARIABLE_POINTER_TRACK Variable
;
626 if (VariableName
== NULL
|| VendorGuid
== NULL
|| DataSize
== NULL
) {
627 return EFI_INVALID_PARAMETER
;
630 // Find existing variable
632 Status
= FindVariable (VariableName
, VendorGuid
, &Variable
, Global
);
634 if (Variable
.CurrPtr
== NULL
|| EFI_ERROR (Status
)) {
640 VarDataSize
= Variable
.CurrPtr
->DataSize
;
641 if (*DataSize
>= VarDataSize
) {
643 Status
= EFI_INVALID_PARAMETER
;
647 CopyMem (Data
, GetVariableDataPtr (Variable
.CurrPtr
), VarDataSize
);
648 if (Attributes
!= NULL
) {
649 *Attributes
= Variable
.CurrPtr
->Attributes
;
652 *DataSize
= VarDataSize
;
653 Status
= EFI_SUCCESS
;
656 *DataSize
= VarDataSize
;
657 Status
= EFI_BUFFER_TOO_SMALL
;
662 ReleaseLockOnlyAtBootTime (&Global
->VariableServicesLock
);
668 GetNextVariableName (
669 IN OUT UINTN
*VariableNameSize
,
670 IN OUT CHAR16
*VariableName
,
671 IN OUT EFI_GUID
*VendorGuid
,
672 IN VARIABLE_GLOBAL
*Global
,
679 This code Finds the Next available variable
683 VariableNameSize Size of the variable
684 VariableName Pointer to variable name
685 VendorGuid Variable Vendor Guid
686 Global VARIABLE_GLOBAL structure pointer.
695 VARIABLE_POINTER_TRACK Variable
;
699 if (VariableNameSize
== NULL
|| VariableName
== NULL
|| VendorGuid
== NULL
) {
700 return EFI_INVALID_PARAMETER
;
703 Status
= FindVariable (VariableName
, VendorGuid
, &Variable
, Global
);
705 if (Variable
.CurrPtr
== NULL
|| EFI_ERROR (Status
)) {
709 if (VariableName
[0] != 0) {
711 // If variable name is not NULL, get next variable
713 Variable
.CurrPtr
= GetNextVariablePtr (Variable
.CurrPtr
);
718 // If both volatile and non-volatile variable store are parsed,
721 if (Variable
.CurrPtr
>= Variable
.EndPtr
|| Variable
.CurrPtr
== NULL
) {
722 Variable
.Volatile
= (BOOLEAN
) (Variable
.Volatile
^ ((BOOLEAN
) 0x1));
723 if (Variable
.Volatile
) {
724 Variable
.StartPtr
= (VARIABLE_HEADER
*) ((UINTN
) (Global
->VolatileVariableBase
+ sizeof (VARIABLE_STORE_HEADER
)));
725 Variable
.EndPtr
= (VARIABLE_HEADER
*) GetEndPointer ((VARIABLE_STORE_HEADER
*) ((UINTN
) Global
->VolatileVariableBase
));
727 Status
= EFI_NOT_FOUND
;
731 Variable
.CurrPtr
= Variable
.StartPtr
;
732 if (!IsValidVariableHeader (Variable
.CurrPtr
)) {
739 if (IsValidVariableHeader (Variable
.CurrPtr
) && Variable
.CurrPtr
->State
== VAR_ADDED
) {
740 if (!(EfiAtRuntime () && !(Variable
.CurrPtr
->Attributes
& EFI_VARIABLE_RUNTIME_ACCESS
))) {
741 VarNameSize
= Variable
.CurrPtr
->NameSize
;
742 if (VarNameSize
<= *VariableNameSize
) {
745 GET_VARIABLE_NAME_PTR (Variable
.CurrPtr
),
750 &Variable
.CurrPtr
->VendorGuid
,
753 Status
= EFI_SUCCESS
;
755 Status
= EFI_BUFFER_TOO_SMALL
;
758 *VariableNameSize
= VarNameSize
;
763 Variable
.CurrPtr
= GetNextVariablePtr (Variable
.CurrPtr
);
767 ReleaseLockOnlyAtBootTime (&Global
->VariableServicesLock
);
774 IN CHAR16
*VariableName
,
775 IN EFI_GUID
*VendorGuid
,
776 IN UINT32 Attributes
,
779 IN VARIABLE_GLOBAL
*Global
,
780 IN UINTN
*VolatileOffset
,
781 IN UINTN
*NonVolatileOffset
,
788 This code sets variable in storage blocks (Volatile or Non-Volatile)
792 VariableName Name of Variable to be found
793 VendorGuid Variable vendor GUID
794 Attributes Attribute value of the variable found
795 DataSize Size of Data found. If size is less than the
796 data, this value contains the required size.
798 Global Pointer to VARIABLE_GLOBAL structure
799 VolatileOffset The offset of last volatile variable
800 NonVolatileOffset The offset of last non-volatile variable
801 Instance Instance of the Firmware Volume.
805 EFI_INVALID_PARAMETER - Invalid parameter
806 EFI_SUCCESS - Set successfully
807 EFI_OUT_OF_RESOURCES - Resource not enough to set variable
808 EFI_NOT_FOUND - Not found
809 EFI_DEVICE_ERROR - Variable can not be saved due to hardware failure
810 EFI_WRITE_PROTECTED - Variable is read-only
814 VARIABLE_POINTER_TRACK Variable
;
816 VARIABLE_HEADER
*NextVariable
;
827 // Check input parameters
829 if (VariableName
== NULL
|| VariableName
[0] == 0 || VendorGuid
== NULL
) {
830 return EFI_INVALID_PARAMETER
;
833 // Make sure if runtime bit is set, boot service bit is set also
835 if ((Attributes
& (EFI_VARIABLE_RUNTIME_ACCESS
| EFI_VARIABLE_BOOTSERVICE_ACCESS
)) == EFI_VARIABLE_RUNTIME_ACCESS
) {
836 return EFI_INVALID_PARAMETER
;
839 // The size of the VariableName, including the Unicode Null in bytes plus
840 // the DataSize is limited to maximum size of MAX_HARDWARE_ERROR_VARIABLE_SIZE (32K)
841 // bytes for HwErrRec, and MAX_VARIABLE_SIZE (1024) bytes for the others.
843 if ((Attributes
& EFI_VARIABLE_HARDWARE_ERROR_RECORD
) == EFI_VARIABLE_HARDWARE_ERROR_RECORD
) {
844 if ((DataSize
> MAX_HARDWARE_ERROR_VARIABLE_SIZE
) ||
845 (sizeof (VARIABLE_HEADER
) + StrSize (VariableName
) + DataSize
> MAX_HARDWARE_ERROR_VARIABLE_SIZE
)) {
846 return EFI_INVALID_PARAMETER
;
850 // The size of the VariableName, including the Unicode Null in bytes plus
851 // the DataSize is limited to maximum size of MAX_VARIABLE_SIZE (1024) bytes.
853 if ((DataSize
> MAX_VARIABLE_SIZE
) ||
854 (sizeof (VARIABLE_HEADER
) + StrSize (VariableName
) + DataSize
> MAX_VARIABLE_SIZE
)) {
855 return EFI_INVALID_PARAMETER
;
859 // Check whether the input variable is already existed
862 Status
= FindVariable (VariableName
, VendorGuid
, &Variable
, Global
);
864 if (Status
== EFI_SUCCESS
&& Variable
.CurrPtr
!= NULL
) {
866 // Update/Delete existing variable
869 if (EfiAtRuntime ()) {
871 // If EfiAtRuntime and the variable is Volatile and Runtime Access,
872 // the volatile is ReadOnly, and SetVariable should be aborted and
873 // return EFI_WRITE_PROTECTED.
875 if (Variable
.Volatile
) {
876 Status
= EFI_WRITE_PROTECTED
;
880 // Only variable have NV attribute can be updated/deleted in Runtime
882 if (!(Variable
.CurrPtr
->Attributes
& EFI_VARIABLE_NON_VOLATILE
)) {
883 Status
= EFI_INVALID_PARAMETER
;
888 // Setting a data variable with no access, or zero DataSize attributes
889 // specified causes it to be deleted.
891 if (DataSize
== 0 || (Attributes
& (EFI_VARIABLE_RUNTIME_ACCESS
| EFI_VARIABLE_BOOTSERVICE_ACCESS
)) == 0) {
892 State
= Variable
.CurrPtr
->State
;
893 State
&= VAR_DELETED
;
895 Status
= UpdateVariableStore (
900 (UINTN
) &Variable
.CurrPtr
->State
,
907 // If the variable is marked valid and the same data has been passed in
908 // then return to the caller immediately.
910 if (Variable
.CurrPtr
->DataSize
== DataSize
&&
911 (CompareMem (Data
, GetVariableDataPtr (Variable
.CurrPtr
), DataSize
) == 0)) {
912 Status
= EFI_SUCCESS
;
914 } else if ((Variable
.CurrPtr
->State
== VAR_ADDED
) ||
915 (Variable
.CurrPtr
->State
== (VAR_ADDED
& VAR_IN_DELETED_TRANSITION
))) {
917 // Mark the old variable as in delete transition
919 State
= Variable
.CurrPtr
->State
;
920 State
&= VAR_IN_DELETED_TRANSITION
;
922 Status
= UpdateVariableStore (
927 (UINTN
) &Variable
.CurrPtr
->State
,
931 if (EFI_ERROR (Status
)) {
935 } else if (Status
== EFI_NOT_FOUND
) {
937 // Create a new variable
941 // Make sure we are trying to create a new variable.
942 // Setting a data variable with no access, or zero DataSize attributes means to delete it.
944 if (DataSize
== 0 || (Attributes
& (EFI_VARIABLE_RUNTIME_ACCESS
| EFI_VARIABLE_BOOTSERVICE_ACCESS
)) == 0) {
945 Status
= EFI_NOT_FOUND
;
950 // Only variable have NV|RT attribute can be created in Runtime
952 if (EfiAtRuntime () &&
953 (!(Attributes
& EFI_VARIABLE_RUNTIME_ACCESS
) || !(Attributes
& EFI_VARIABLE_NON_VOLATILE
))) {
954 Status
= EFI_INVALID_PARAMETER
;
959 // Status should be EFI_INVALID_PARAMETER here according to return status of FindVariable().
961 ASSERT (Status
== EFI_INVALID_PARAMETER
);
966 // Function part - create a new variable and copy the data.
967 // Both update a variable and create a variable will come here.
969 // Tricky part: Use scratch data area at the end of volatile variable store
970 // as a temporary storage.
972 NextVariable
= GetEndPointer ((VARIABLE_STORE_HEADER
*) ((UINTN
) Global
->VolatileVariableBase
));
974 SetMem (NextVariable
, SCRATCH_SIZE
, 0xff);
976 NextVariable
->StartId
= VARIABLE_DATA
;
977 NextVariable
->Attributes
= Attributes
;
979 // NextVariable->State = VAR_ADDED;
981 NextVariable
->Reserved
= 0;
982 VarNameOffset
= sizeof (VARIABLE_HEADER
);
983 VarNameSize
= StrSize (VariableName
);
985 (UINT8
*) ((UINTN
) NextVariable
+ VarNameOffset
),
989 VarDataOffset
= VarNameOffset
+ VarNameSize
+ GET_PAD_SIZE (VarNameSize
);
991 (UINT8
*) ((UINTN
) NextVariable
+ VarDataOffset
),
995 CopyMem (&NextVariable
->VendorGuid
, VendorGuid
, sizeof (EFI_GUID
));
997 // There will be pad bytes after Data, the NextVariable->NameSize and
998 // NextVariable->DataSize should not include pad size so that variable
999 // service can get actual size in GetVariable
1001 NextVariable
->NameSize
= (UINT32
)VarNameSize
;
1002 NextVariable
->DataSize
= (UINT32
)DataSize
;
1005 // The actual size of the variable that stores in storage should
1006 // include pad size.
1008 VarSize
= VarDataOffset
+ DataSize
+ GET_PAD_SIZE (DataSize
);
1009 if (Attributes
& EFI_VARIABLE_NON_VOLATILE
) {
1011 // Create a nonvolatile variable
1014 if ((UINT32
) (VarSize
+*NonVolatileOffset
) >
1015 ((VARIABLE_STORE_HEADER
*) ((UINTN
) (Global
->NonVolatileVariableBase
)))->Size
1017 if (EfiAtRuntime ()) {
1018 Status
= EFI_OUT_OF_RESOURCES
;
1022 // Perform garbage collection & reclaim operation
1024 Status
= Reclaim (Global
->NonVolatileVariableBase
, NonVolatileOffset
, FALSE
);
1025 if (EFI_ERROR (Status
)) {
1029 // If still no enough space, return out of resources
1031 if ((UINT32
) (VarSize
+*NonVolatileOffset
) >
1032 ((VARIABLE_STORE_HEADER
*) ((UINTN
) (Global
->NonVolatileVariableBase
)))->Size
1034 Status
= EFI_OUT_OF_RESOURCES
;
1042 // 1. Write variable header
1043 // 2. Write variable data
1044 // 3. Set variable state to valid
1049 Status
= UpdateVariableStore (
1055 sizeof (VARIABLE_HEADER
),
1056 (UINT8
*) NextVariable
1059 if (EFI_ERROR (Status
)) {
1065 Status
= UpdateVariableStore (
1070 *NonVolatileOffset
+ sizeof (VARIABLE_HEADER
),
1071 (UINT32
) VarSize
- sizeof (VARIABLE_HEADER
),
1072 (UINT8
*) NextVariable
+ sizeof (VARIABLE_HEADER
)
1075 if (EFI_ERROR (Status
)) {
1081 NextVariable
->State
= VAR_ADDED
;
1082 Status
= UpdateVariableStore (
1088 sizeof (VARIABLE_HEADER
),
1089 (UINT8
*) NextVariable
1092 if (EFI_ERROR (Status
)) {
1096 *NonVolatileOffset
= *NonVolatileOffset
+ VarSize
;
1100 // Create a volatile variable
1103 if ((UINT32
) (VarSize
+*VolatileOffset
) >
1104 ((VARIABLE_STORE_HEADER
*) ((UINTN
) (Global
->VolatileVariableBase
)))->Size
) {
1106 // Perform garbage collection & reclaim operation
1108 Status
= Reclaim (Global
->VolatileVariableBase
, VolatileOffset
, TRUE
);
1109 if (EFI_ERROR (Status
)) {
1113 // If still no enough space, return out of resources
1115 if ((UINT32
) (VarSize
+*VolatileOffset
) >
1116 ((VARIABLE_STORE_HEADER
*) ((UINTN
) (Global
->VolatileVariableBase
)))->Size
1118 Status
= EFI_OUT_OF_RESOURCES
;
1125 NextVariable
->State
= VAR_ADDED
;
1126 Status
= UpdateVariableStore (
1133 (UINT8
*) NextVariable
1136 if (EFI_ERROR (Status
)) {
1140 *VolatileOffset
= *VolatileOffset
+ VarSize
;
1143 // Mark the old variable as deleted
1145 if (!Reclaimed
&& !EFI_ERROR (Status
) && Variable
.CurrPtr
!= NULL
) {
1146 State
= Variable
.CurrPtr
->State
;
1147 State
&= VAR_DELETED
;
1149 Status
= UpdateVariableStore (
1154 (UINTN
) &Variable
.CurrPtr
->State
,
1161 Status
= EFI_SUCCESS
;
1163 ReleaseLockOnlyAtBootTime (&Global
->VariableServicesLock
);
1170 IN UINT32 Attributes
,
1171 OUT UINT64
*MaximumVariableStorageSize
,
1172 OUT UINT64
*RemainingVariableStorageSize
,
1173 OUT UINT64
*MaximumVariableSize
,
1174 IN VARIABLE_GLOBAL
*Global
,
1179 Routine Description:
1181 This code returns information about the EFI variables.
1185 Attributes Attributes bitmask to specify the type of variables
1186 on which to return information.
1187 MaximumVariableStorageSize Pointer to the maximum size of the storage space available
1188 for the EFI variables associated with the attributes specified.
1189 RemainingVariableStorageSize Pointer to the remaining size of the storage space available
1190 for EFI variables associated with the attributes specified.
1191 MaximumVariableSize Pointer to the maximum size of an individual EFI variables
1192 associated with the attributes specified.
1193 Global Pointer to VARIABLE_GLOBAL structure.
1194 Instance Instance of the Firmware Volume.
1199 EFI_INVALID_PARAMETER - An invalid combination of attribute bits was supplied.
1200 EFI_SUCCESS - Query successfully.
1201 EFI_UNSUPPORTED - The attribute is not supported on this platform.
1205 VARIABLE_HEADER
*Variable
;
1206 VARIABLE_HEADER
*NextVariable
;
1207 UINT64 VariableSize
;
1208 VARIABLE_STORE_HEADER
*VariableStoreHeader
;
1210 if(MaximumVariableStorageSize
== NULL
|| RemainingVariableStorageSize
== NULL
|| MaximumVariableSize
== NULL
|| Attributes
== 0) {
1211 return EFI_INVALID_PARAMETER
;
1214 if((Attributes
& (EFI_VARIABLE_NON_VOLATILE
| EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_RUNTIME_ACCESS
| EFI_VARIABLE_HARDWARE_ERROR_RECORD
)) == 0) {
1216 // Make sure the Attributes combination is supported by the platform.
1218 return EFI_UNSUPPORTED
;
1219 } else if ((Attributes
& (EFI_VARIABLE_RUNTIME_ACCESS
| EFI_VARIABLE_BOOTSERVICE_ACCESS
)) == EFI_VARIABLE_RUNTIME_ACCESS
) {
1221 // Make sure if runtime bit is set, boot service bit is set also.
1223 return EFI_INVALID_PARAMETER
;
1224 } else if (EfiAtRuntime () && !(Attributes
& EFI_VARIABLE_RUNTIME_ACCESS
)) {
1226 // Make sure RT Attribute is set if we are in Runtime phase.
1228 return EFI_INVALID_PARAMETER
;
1231 AcquireLockOnlyAtBootTime(&Global
->VariableServicesLock
);
1233 if((Attributes
& EFI_VARIABLE_NON_VOLATILE
) == 0) {
1235 // Query is Volatile related.
1237 VariableStoreHeader
= (VARIABLE_STORE_HEADER
*) ((UINTN
) Global
->VolatileVariableBase
);
1240 // Query is Non-Volatile related.
1242 VariableStoreHeader
= (VARIABLE_STORE_HEADER
*) ((UINTN
) Global
->NonVolatileVariableBase
);
1246 // Now let's fill *MaximumVariableStorageSize *RemainingVariableStorageSize
1247 // with the storage size (excluding the storage header size).
1249 *MaximumVariableStorageSize
= VariableStoreHeader
->Size
- sizeof (VARIABLE_STORE_HEADER
);
1250 *RemainingVariableStorageSize
= VariableStoreHeader
->Size
- sizeof (VARIABLE_STORE_HEADER
);
1253 // Let *MaximumVariableSize be MAX_VARIABLE_SIZE with the exception of the variable header size.
1255 *MaximumVariableSize
= MAX_VARIABLE_SIZE
- sizeof (VARIABLE_HEADER
);
1258 // Harware error record variable needs larger size.
1260 if ((Attributes
& EFI_VARIABLE_HARDWARE_ERROR_RECORD
) == EFI_VARIABLE_HARDWARE_ERROR_RECORD
) {
1261 *MaximumVariableSize
= MAX_HARDWARE_ERROR_VARIABLE_SIZE
- sizeof (VARIABLE_HEADER
);
1265 // Point to the starting address of the variables.
1267 Variable
= (VARIABLE_HEADER
*) (VariableStoreHeader
+ 1);
1270 // Now walk through the related variable store.
1272 while (IsValidVariableHeader (Variable
) && (Variable
< GetEndPointer (VariableStoreHeader
))) {
1273 NextVariable
= GetNextVariablePtr (Variable
);
1274 VariableSize
= (UINT64
) (UINTN
) NextVariable
- (UINT64
) (UINTN
) Variable
;
1276 if (EfiAtRuntime ()) {
1278 // we don't take the state of the variables in mind
1279 // when calculating RemainingVariableStorageSize,
1280 // since the space occupied by variables not marked with
1281 // VAR_ADDED is not allowed to be reclaimed in Runtime.
1283 *RemainingVariableStorageSize
-= VariableSize
;
1286 // Only care about Variables with State VAR_ADDED,because
1287 // the space not marked as VAR_ADDED is reclaimable now.
1289 if (Variable
->State
== VAR_ADDED
) {
1290 *RemainingVariableStorageSize
-= VariableSize
;
1295 // Go to the next one
1297 Variable
= NextVariable
;
1300 if (*RemainingVariableStorageSize
< sizeof (VARIABLE_HEADER
)) {
1301 *MaximumVariableSize
= 0;
1302 } else if ((*RemainingVariableStorageSize
- sizeof (VARIABLE_HEADER
)) < *MaximumVariableSize
) {
1303 *MaximumVariableSize
= *RemainingVariableStorageSize
- sizeof (VARIABLE_HEADER
);
1306 ReleaseLockOnlyAtBootTime (&Global
->VariableServicesLock
);
1312 VariableCommonInitialize (
1313 IN EFI_HANDLE ImageHandle
,
1314 IN EFI_SYSTEM_TABLE
*SystemTable
1318 Routine Description:
1319 This function does common initialization for variable services
1323 ImageHandle - The firmware allocated handle for the EFI image.
1324 SystemTable - A pointer to the EFI System Table.
1330 EFI_NOT_FOUND - Variable store area not found.
1331 EFI_UNSUPPORTED - Currently only one non-volatile variable store is supported.
1332 EFI_SUCCESS - Variable services successfully initialized.
1337 EFI_FIRMWARE_VOLUME_HEADER
*FwVolHeader
;
1339 VARIABLE_STORE_HEADER
*VolatileVariableStore
;
1340 VARIABLE_STORE_HEADER
*VariableStoreHeader
;
1341 VARIABLE_HEADER
*NextVariable
;
1343 EFI_PHYSICAL_ADDRESS FvVolHdr
;
1344 UINT64 TempVariableStoreHeader
;
1345 EFI_GCD_MEMORY_SPACE_DESCRIPTOR GcdDescriptor
;
1346 EFI_FLASH_SUBAREA_ENTRY VariableStoreEntry
;
1352 mVariableModuleGlobal
= AllocateRuntimePool (sizeof (ESAL_VARIABLE_GLOBAL
));
1353 if (mVariableModuleGlobal
== NULL
) {
1354 return EFI_OUT_OF_RESOURCES
;
1357 EfiInitializeLock(&mVariableModuleGlobal
->VariableGlobal
[Physical
].VariableServicesLock
, TPL_NOTIFY
);
1360 // Allocate memory for volatile variable store
1362 VolatileVariableStore
= AllocateRuntimePool (VARIABLE_STORE_SIZE
+ SCRATCH_SIZE
);
1363 if (VolatileVariableStore
== NULL
) {
1364 FreePool (mVariableModuleGlobal
);
1365 return EFI_OUT_OF_RESOURCES
;
1368 SetMem (VolatileVariableStore
, VARIABLE_STORE_SIZE
+ SCRATCH_SIZE
, 0xff);
1371 // Variable Specific Data
1373 mVariableModuleGlobal
->VariableGlobal
[Physical
].VolatileVariableBase
= (EFI_PHYSICAL_ADDRESS
) (UINTN
) VolatileVariableStore
;
1374 mVariableModuleGlobal
->VolatileLastVariableOffset
= sizeof (VARIABLE_STORE_HEADER
);
1376 VolatileVariableStore
->Signature
= VARIABLE_STORE_SIGNATURE
;
1377 VolatileVariableStore
->Size
= VARIABLE_STORE_SIZE
;
1378 VolatileVariableStore
->Format
= VARIABLE_STORE_FORMATTED
;
1379 VolatileVariableStore
->State
= VARIABLE_STORE_HEALTHY
;
1380 VolatileVariableStore
->Reserved
= 0;
1381 VolatileVariableStore
->Reserved1
= 0;
1384 // Get non volatile varaible store
1387 TempVariableStoreHeader
= (UINT64
) PcdGet32 (PcdFlashNvStorageVariableBase
);
1388 VariableStoreEntry
.Base
= TempVariableStoreHeader
+ \
1389 (((EFI_FIRMWARE_VOLUME_HEADER
*) (UINTN
) (TempVariableStoreHeader
)) -> HeaderLength
);
1390 VariableStoreEntry
.Length
= (UINT64
) PcdGet32 (PcdFlashNvStorageVariableSize
) - \
1391 (((EFI_FIRMWARE_VOLUME_HEADER
*) (UINTN
) (TempVariableStoreHeader
)) -> HeaderLength
);
1393 // Mark the variable storage region of the FLASH as RUNTIME
1395 BaseAddress
= VariableStoreEntry
.Base
& (~EFI_PAGE_MASK
);
1396 Length
= VariableStoreEntry
.Length
+ (VariableStoreEntry
.Base
- BaseAddress
);
1397 Length
= (Length
+ EFI_PAGE_SIZE
- 1) & (~EFI_PAGE_MASK
);
1399 Status
= gDS
->GetMemorySpaceDescriptor (BaseAddress
, &GcdDescriptor
);
1400 if (EFI_ERROR (Status
)) {
1401 FreePool (mVariableModuleGlobal
);
1402 FreePool (VolatileVariableStore
);
1403 return EFI_UNSUPPORTED
;
1406 Status
= gDS
->SetMemorySpaceAttributes (
1409 GcdDescriptor
.Attributes
| EFI_MEMORY_RUNTIME
1411 if (EFI_ERROR (Status
)) {
1412 FreePool (mVariableModuleGlobal
);
1413 FreePool (VolatileVariableStore
);
1414 return EFI_UNSUPPORTED
;
1417 // Get address of non volatile variable store base
1419 mVariableModuleGlobal
->VariableGlobal
[Physical
].NonVolatileVariableBase
= VariableStoreEntry
.Base
;
1425 // Find the Correct Instance of the FV Block Service.
1428 CurrPtr
= (CHAR8
*) ((UINTN
) mVariableModuleGlobal
->VariableGlobal
[Physical
].NonVolatileVariableBase
);
1429 while (EfiFvbGetPhysicalAddress (Instance
, &FvVolHdr
) == EFI_SUCCESS
) {
1430 FwVolHeader
= (EFI_FIRMWARE_VOLUME_HEADER
*) ((UINTN
) FvVolHdr
);
1431 if (CurrPtr
>= (CHAR8
*) FwVolHeader
&& CurrPtr
< (((CHAR8
*) FwVolHeader
) + FwVolHeader
->FvLength
)) {
1432 mVariableModuleGlobal
->FvbInstance
= Instance
;
1439 VariableStoreHeader
= (VARIABLE_STORE_HEADER
*) CurrPtr
;
1440 if (GetVariableStoreStatus (VariableStoreHeader
) == EfiValid
) {
1441 if (~VariableStoreHeader
->Size
== 0) {
1442 Status
= UpdateVariableStore (
1443 &mVariableModuleGlobal
->VariableGlobal
[Physical
],
1446 mVariableModuleGlobal
->FvbInstance
,
1447 (UINTN
) &VariableStoreHeader
->Size
,
1449 (UINT8
*) &VariableStoreEntry
.Length
1452 // As Variables are stored in NV storage, which are slow devices,such as flash.
1453 // Variable operation may skip checking variable program result to improve performance,
1454 // We can assume Variable program is OK through some check point.
1455 // Variable Store Size Setting should be the first Variable write operation,
1456 // We can assume all Read/Write is OK if we can set Variable store size successfully.
1457 // If write fail, we will assert here
1459 ASSERT(VariableStoreHeader
->Size
== VariableStoreEntry
.Length
);
1461 if (EFI_ERROR (Status
)) {
1466 mVariableModuleGlobal
->VariableGlobal
[Physical
].NonVolatileVariableBase
= (EFI_PHYSICAL_ADDRESS
) ((UINTN
) CurrPtr
);
1468 // Parse non-volatile variable data and get last variable offset
1470 NextVariable
= (VARIABLE_HEADER
*) (CurrPtr
+ sizeof (VARIABLE_STORE_HEADER
));
1471 Status
= EFI_SUCCESS
;
1473 while (IsValidVariableHeader (NextVariable
)) {
1474 NextVariable
= GetNextVariablePtr (NextVariable
);
1477 mVariableModuleGlobal
->NonVolatileLastVariableOffset
= (UINTN
) NextVariable
- (UINTN
) CurrPtr
;
1480 // Check if the free area is blow a threshold
1482 if ((((VARIABLE_STORE_HEADER
*)((UINTN
) CurrPtr
))->Size
- mVariableModuleGlobal
->NonVolatileLastVariableOffset
) < VARIABLE_RECLAIM_THRESHOLD
) {
1484 mVariableModuleGlobal
->VariableGlobal
[Physical
].NonVolatileVariableBase
,
1485 &mVariableModuleGlobal
->NonVolatileLastVariableOffset
,
1490 if (EFI_ERROR (Status
)) {
1491 FreePool (mVariableModuleGlobal
);
1492 FreePool (VolatileVariableStore
);
1497 // Check if the free area is really free.
1499 for (Index
= mVariableModuleGlobal
->NonVolatileLastVariableOffset
; Index
< VariableStoreHeader
->Size
; Index
++) {
1500 Data
= ((UINT8
*) (UINTN
) mVariableModuleGlobal
->VariableGlobal
[Physical
].NonVolatileVariableBase
)[Index
];
1503 // There must be something wrong in variable store, do reclaim operation.
1506 mVariableModuleGlobal
->VariableGlobal
[Physical
].NonVolatileVariableBase
,
1507 &mVariableModuleGlobal
->NonVolatileLastVariableOffset
,
1515 if (EFI_ERROR (Status
)) {
1516 FreePool (mVariableModuleGlobal
);
1517 FreePool (VolatileVariableStore
);