2 The common variable operation routines shared by DXE_RUNTIME variable
3 module and DXE_SMM variable module.
5 Caution: This module requires additional review when modified.
6 This driver will have external input - variable data. They may be input in SMM mode.
7 This external input must be validated carefully to avoid security issue like
8 buffer overflow, integer overflow.
10 VariableServiceGetNextVariableName () and VariableServiceQueryVariableInfo() are external API.
11 They need check input parameter.
13 VariableServiceGetVariable() and VariableServiceSetVariable() are external API
14 to receive datasize and data buffer. The size should be checked carefully.
16 VariableServiceSetVariable() should also check authenticate data to avoid buffer overflow,
17 integer overflow. It should also check attribute to avoid authentication bypass.
19 Copyright (c) 2009 - 2015, Intel Corporation. All rights reserved.<BR>
20 This program and the accompanying materials
21 are licensed and made available under the terms and conditions of the BSD License
22 which accompanies this distribution. The full text of the license may be found at
23 http://opensource.org/licenses/bsd-license.php
25 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
26 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
31 #include "AuthService.h"
33 VARIABLE_MODULE_GLOBAL
*mVariableModuleGlobal
;
36 /// Define a memory cache that improves the search performance for a variable.
38 VARIABLE_STORE_HEADER
*mNvVariableCache
= NULL
;
41 /// The memory entry used for variable statistics data.
43 VARIABLE_INFO_ENTRY
*gVariableInfo
= NULL
;
46 /// The list to store the variables which cannot be set after the EFI_END_OF_DXE_EVENT_GROUP_GUID
47 /// or EVT_GROUP_READY_TO_BOOT event.
49 LIST_ENTRY mLockedVariableList
= INITIALIZE_LIST_HEAD_VARIABLE (mLockedVariableList
);
52 /// The flag to indicate whether the platform has left the DXE phase of execution.
54 BOOLEAN mEndOfDxe
= FALSE
;
57 /// The flag to indicate whether the variable storage locking is enabled.
59 BOOLEAN mEnableLocking
= TRUE
;
63 SecureBoot Hook for auth variable update.
65 @param[in] VariableName Name of Variable to be found.
66 @param[in] VendorGuid Variable vendor GUID.
71 IN CHAR16
*VariableName
,
72 IN EFI_GUID
*VendorGuid
76 Routine used to track statistical information about variable usage.
77 The data is stored in the EFI system table so it can be accessed later.
78 VariableInfo.efi can dump out the table. Only Boot Services variable
79 accesses are tracked by this code. The PcdVariableCollectStatistics
80 build flag controls if this feature is enabled.
82 A read that hits in the cache will have Read and Cache true for
83 the transaction. Data is allocated by this routine, but never
86 @param[in] VariableName Name of the Variable to track.
87 @param[in] VendorGuid Guid of the Variable to track.
88 @param[in] Volatile TRUE if volatile FALSE if non-volatile.
89 @param[in] Read TRUE if GetVariable() was called.
90 @param[in] Write TRUE if SetVariable() was called.
91 @param[in] Delete TRUE if deleted via SetVariable().
92 @param[in] Cache TRUE for a cache hit.
97 IN CHAR16
*VariableName
,
98 IN EFI_GUID
*VendorGuid
,
106 VARIABLE_INFO_ENTRY
*Entry
;
108 if (FeaturePcdGet (PcdVariableCollectStatistics
)) {
111 // Don't collect statistics at runtime.
115 if (gVariableInfo
== NULL
) {
117 // On the first call allocate a entry and place a pointer to it in
118 // the EFI System Table.
120 gVariableInfo
= AllocateZeroPool (sizeof (VARIABLE_INFO_ENTRY
));
121 ASSERT (gVariableInfo
!= NULL
);
123 CopyGuid (&gVariableInfo
->VendorGuid
, VendorGuid
);
124 gVariableInfo
->Name
= AllocatePool (StrSize (VariableName
));
125 ASSERT (gVariableInfo
->Name
!= NULL
);
126 StrCpy (gVariableInfo
->Name
, VariableName
);
127 gVariableInfo
->Volatile
= Volatile
;
131 for (Entry
= gVariableInfo
; Entry
!= NULL
; Entry
= Entry
->Next
) {
132 if (CompareGuid (VendorGuid
, &Entry
->VendorGuid
)) {
133 if (StrCmp (VariableName
, Entry
->Name
) == 0) {
141 Entry
->DeleteCount
++;
151 if (Entry
->Next
== NULL
) {
153 // If the entry is not in the table add it.
154 // Next iteration of the loop will fill in the data.
156 Entry
->Next
= AllocateZeroPool (sizeof (VARIABLE_INFO_ENTRY
));
157 ASSERT (Entry
->Next
!= NULL
);
159 CopyGuid (&Entry
->Next
->VendorGuid
, VendorGuid
);
160 Entry
->Next
->Name
= AllocatePool (StrSize (VariableName
));
161 ASSERT (Entry
->Next
->Name
!= NULL
);
162 StrCpy (Entry
->Next
->Name
, VariableName
);
163 Entry
->Next
->Volatile
= Volatile
;
173 This code checks if variable header is valid or not.
175 @param Variable Pointer to the Variable Header.
176 @param VariableStoreEnd Pointer to the Variable Store End.
178 @retval TRUE Variable header is valid.
179 @retval FALSE Variable header is not valid.
183 IsValidVariableHeader (
184 IN VARIABLE_HEADER
*Variable
,
185 IN VARIABLE_HEADER
*VariableStoreEnd
188 if ((Variable
== NULL
) || (Variable
>= VariableStoreEnd
) || (Variable
->StartId
!= VARIABLE_DATA
)) {
190 // Variable is NULL or has reached the end of variable store,
191 // or the StartId is not correct.
202 This function writes data to the FWH at the correct LBA even if the LBAs
205 @param Global Pointer to VARAIBLE_GLOBAL structure.
206 @param Volatile Point out the Variable is Volatile or Non-Volatile.
207 @param SetByIndex TRUE if target pointer is given as index.
208 FALSE if target pointer is absolute.
209 @param Fvb Pointer to the writable FVB protocol.
210 @param DataPtrIndex Pointer to the Data from the end of VARIABLE_STORE_HEADER
212 @param DataSize Size of data to be written.
213 @param Buffer Pointer to the buffer from which data is written.
215 @retval EFI_INVALID_PARAMETER Parameters not valid.
216 @retval EFI_SUCCESS Variable store successfully updated.
220 UpdateVariableStore (
221 IN VARIABLE_GLOBAL
*Global
,
223 IN BOOLEAN SetByIndex
,
224 IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*Fvb
,
225 IN UINTN DataPtrIndex
,
230 EFI_FV_BLOCK_MAP_ENTRY
*PtrBlockMapEntry
;
238 EFI_FIRMWARE_VOLUME_HEADER
*FwVolHeader
;
239 VARIABLE_STORE_HEADER
*VolatileBase
;
240 EFI_PHYSICAL_ADDRESS FvVolHdr
;
241 EFI_PHYSICAL_ADDRESS DataPtr
;
245 DataPtr
= DataPtrIndex
;
248 // Check if the Data is Volatile.
252 return EFI_INVALID_PARAMETER
;
254 Status
= Fvb
->GetPhysicalAddress(Fvb
, &FvVolHdr
);
255 ASSERT_EFI_ERROR (Status
);
257 FwVolHeader
= (EFI_FIRMWARE_VOLUME_HEADER
*) ((UINTN
) FvVolHdr
);
259 // Data Pointer should point to the actual Address where data is to be
263 DataPtr
+= mVariableModuleGlobal
->VariableGlobal
.NonVolatileVariableBase
;
266 if ((DataPtr
+ DataSize
) >= ((EFI_PHYSICAL_ADDRESS
) (UINTN
) ((UINT8
*) FwVolHeader
+ FwVolHeader
->FvLength
))) {
267 return EFI_INVALID_PARAMETER
;
271 // Data Pointer should point to the actual Address where data is to be
274 VolatileBase
= (VARIABLE_STORE_HEADER
*) ((UINTN
) mVariableModuleGlobal
->VariableGlobal
.VolatileVariableBase
);
276 DataPtr
+= mVariableModuleGlobal
->VariableGlobal
.VolatileVariableBase
;
279 if ((DataPtr
+ DataSize
) >= ((UINTN
) ((UINT8
*) VolatileBase
+ VolatileBase
->Size
))) {
280 return EFI_INVALID_PARAMETER
;
284 // If Volatile Variable just do a simple mem copy.
286 CopyMem ((UINT8
*)(UINTN
)DataPtr
, Buffer
, DataSize
);
291 // If we are here we are dealing with Non-Volatile Variables.
293 LinearOffset
= (UINTN
) FwVolHeader
;
294 CurrWritePtr
= (UINTN
) DataPtr
;
295 CurrWriteSize
= DataSize
;
299 if (CurrWritePtr
< LinearOffset
) {
300 return EFI_INVALID_PARAMETER
;
303 for (PtrBlockMapEntry
= FwVolHeader
->BlockMap
; PtrBlockMapEntry
->NumBlocks
!= 0; PtrBlockMapEntry
++) {
304 for (BlockIndex2
= 0; BlockIndex2
< PtrBlockMapEntry
->NumBlocks
; BlockIndex2
++) {
306 // Check to see if the Variable Writes are spanning through multiple
309 if ((CurrWritePtr
>= LinearOffset
) && (CurrWritePtr
< LinearOffset
+ PtrBlockMapEntry
->Length
)) {
310 if ((CurrWritePtr
+ CurrWriteSize
) <= (LinearOffset
+ PtrBlockMapEntry
->Length
)) {
311 Status
= Fvb
->Write (
314 (UINTN
) (CurrWritePtr
- LinearOffset
),
320 Size
= (UINT32
) (LinearOffset
+ PtrBlockMapEntry
->Length
- CurrWritePtr
);
321 Status
= Fvb
->Write (
324 (UINTN
) (CurrWritePtr
- LinearOffset
),
328 if (EFI_ERROR (Status
)) {
332 CurrWritePtr
= LinearOffset
+ PtrBlockMapEntry
->Length
;
333 CurrBuffer
= CurrBuffer
+ Size
;
334 CurrWriteSize
= CurrWriteSize
- Size
;
338 LinearOffset
+= PtrBlockMapEntry
->Length
;
349 This code gets the current status of Variable Store.
351 @param VarStoreHeader Pointer to the Variable Store Header.
353 @retval EfiRaw Variable store status is raw.
354 @retval EfiValid Variable store status is valid.
355 @retval EfiInvalid Variable store status is invalid.
358 VARIABLE_STORE_STATUS
359 GetVariableStoreStatus (
360 IN VARIABLE_STORE_HEADER
*VarStoreHeader
363 if (CompareGuid (&VarStoreHeader
->Signature
, &gEfiAuthenticatedVariableGuid
) &&
364 VarStoreHeader
->Format
== VARIABLE_STORE_FORMATTED
&&
365 VarStoreHeader
->State
== VARIABLE_STORE_HEALTHY
369 } else if (((UINT32
*)(&VarStoreHeader
->Signature
))[0] == 0xffffffff &&
370 ((UINT32
*)(&VarStoreHeader
->Signature
))[1] == 0xffffffff &&
371 ((UINT32
*)(&VarStoreHeader
->Signature
))[2] == 0xffffffff &&
372 ((UINT32
*)(&VarStoreHeader
->Signature
))[3] == 0xffffffff &&
373 VarStoreHeader
->Size
== 0xffffffff &&
374 VarStoreHeader
->Format
== 0xff &&
375 VarStoreHeader
->State
== 0xff
387 This code gets the size of name of variable.
389 @param Variable Pointer to the Variable Header.
391 @return UINTN Size of variable in bytes.
396 IN VARIABLE_HEADER
*Variable
399 if (Variable
->State
== (UINT8
) (-1) ||
400 Variable
->DataSize
== (UINT32
) (-1) ||
401 Variable
->NameSize
== (UINT32
) (-1) ||
402 Variable
->Attributes
== (UINT32
) (-1)) {
405 return (UINTN
) Variable
->NameSize
;
410 This code gets the size of variable data.
412 @param Variable Pointer to the Variable Header.
414 @return Size of variable in bytes.
419 IN VARIABLE_HEADER
*Variable
422 if (Variable
->State
== (UINT8
) (-1) ||
423 Variable
->DataSize
== (UINT32
) (-1) ||
424 Variable
->NameSize
== (UINT32
) (-1) ||
425 Variable
->Attributes
== (UINT32
) (-1)) {
428 return (UINTN
) Variable
->DataSize
;
433 This code gets the pointer to the variable name.
435 @param Variable Pointer to the Variable Header.
437 @return Pointer to Variable Name which is Unicode encoding.
442 IN VARIABLE_HEADER
*Variable
446 return (CHAR16
*) (Variable
+ 1);
451 This code gets the pointer to the variable data.
453 @param Variable Pointer to the Variable Header.
455 @return Pointer to Variable Data.
460 IN VARIABLE_HEADER
*Variable
466 // Be careful about pad size for alignment.
468 Value
= (UINTN
) GetVariableNamePtr (Variable
);
469 Value
+= NameSizeOfVariable (Variable
);
470 Value
+= GET_PAD_SIZE (NameSizeOfVariable (Variable
));
472 return (UINT8
*) Value
;
478 This code gets the pointer to the next variable header.
480 @param Variable Pointer to the Variable Header.
482 @return Pointer to next variable header.
487 IN VARIABLE_HEADER
*Variable
492 Value
= (UINTN
) GetVariableDataPtr (Variable
);
493 Value
+= DataSizeOfVariable (Variable
);
494 Value
+= GET_PAD_SIZE (DataSizeOfVariable (Variable
));
497 // Be careful about pad size for alignment.
499 return (VARIABLE_HEADER
*) HEADER_ALIGN (Value
);
504 Gets the pointer to the first variable header in given variable store area.
506 @param VarStoreHeader Pointer to the Variable Store Header.
508 @return Pointer to the first variable header.
513 IN VARIABLE_STORE_HEADER
*VarStoreHeader
517 // The end of variable store.
519 return (VARIABLE_HEADER
*) HEADER_ALIGN (VarStoreHeader
+ 1);
524 Gets the pointer to the end of the variable storage area.
526 This function gets pointer to the end of the variable storage
527 area, according to the input variable store header.
529 @param VarStoreHeader Pointer to the Variable Store Header.
531 @return Pointer to the end of the variable storage area.
536 IN VARIABLE_STORE_HEADER
*VarStoreHeader
540 // The end of variable store
542 return (VARIABLE_HEADER
*) HEADER_ALIGN ((UINTN
) VarStoreHeader
+ VarStoreHeader
->Size
);
547 Check the PubKeyIndex is a valid key or not.
549 This function will iterate the NV storage to see if this PubKeyIndex is still referenced
550 by any valid count-based auth variabe.
552 @param[in] PubKeyIndex Index of the public key in public key store.
554 @retval TRUE The PubKeyIndex is still in use.
555 @retval FALSE The PubKeyIndex is not referenced by any count-based auth variabe.
560 IN UINT32 PubKeyIndex
563 VARIABLE_HEADER
*Variable
;
564 VARIABLE_HEADER
*VariableStoreEnd
;
566 if (PubKeyIndex
> mPubKeyNumber
) {
570 Variable
= GetStartPointer ((VARIABLE_STORE_HEADER
*) (UINTN
) mVariableModuleGlobal
->VariableGlobal
.NonVolatileVariableBase
);
571 VariableStoreEnd
= GetEndPointer ((VARIABLE_STORE_HEADER
*) (UINTN
) mVariableModuleGlobal
->VariableGlobal
.NonVolatileVariableBase
);
573 while (IsValidVariableHeader (Variable
, VariableStoreEnd
)) {
574 if ((Variable
->State
== VAR_ADDED
|| Variable
->State
== (VAR_IN_DELETED_TRANSITION
& VAR_ADDED
)) &&
575 Variable
->PubKeyIndex
== PubKeyIndex
) {
578 Variable
= GetNextVariablePtr (Variable
);
586 Get the number of valid public key in PubKeyStore.
588 @param[in] PubKeyNumber Number of the public key in public key store.
590 @return Number of valid public key in PubKeyStore.
594 GetValidPubKeyNumber (
595 IN UINT32 PubKeyNumber
603 for (PubKeyIndex
= 1; PubKeyIndex
<= PubKeyNumber
; PubKeyIndex
++) {
604 if (IsValidPubKeyIndex (PubKeyIndex
)) {
614 Filter the useless key in public key store.
616 This function will find out all valid public keys in public key database, save them in new allocated
617 buffer NewPubKeyStore, and give the new PubKeyIndex. The caller is responsible for freeing buffer
618 NewPubKeyIndex and NewPubKeyStore with FreePool().
620 @param[in] PubKeyStore Point to the public key database.
621 @param[in] PubKeyNumber Number of the public key in PubKeyStore.
622 @param[out] NewPubKeyIndex Point to an array of new PubKeyIndex corresponds to NewPubKeyStore.
623 @param[out] NewPubKeyStore Saved all valid public keys in PubKeyStore.
624 @param[out] NewPubKeySize Buffer size of the NewPubKeyStore.
626 @retval EFI_SUCCESS Trim operation is complete successfully.
627 @retval EFI_OUT_OF_RESOURCES No enough memory resources, or no useless key in PubKeyStore.
632 IN UINT8
*PubKeyStore
,
633 IN UINT32 PubKeyNumber
,
634 OUT UINT32
**NewPubKeyIndex
,
635 OUT UINT8
**NewPubKeyStore
,
636 OUT UINT32
*NewPubKeySize
641 UINT32 NewPubKeyNumber
;
643 NewPubKeyNumber
= GetValidPubKeyNumber (PubKeyNumber
);
644 if (NewPubKeyNumber
== PubKeyNumber
) {
645 return EFI_OUT_OF_RESOURCES
;
648 if (NewPubKeyNumber
!= 0) {
649 *NewPubKeySize
= NewPubKeyNumber
* EFI_CERT_TYPE_RSA2048_SIZE
;
651 *NewPubKeySize
= sizeof (UINT8
);
654 *NewPubKeyStore
= AllocatePool (*NewPubKeySize
);
655 if (*NewPubKeyStore
== NULL
) {
656 return EFI_OUT_OF_RESOURCES
;
659 *NewPubKeyIndex
= AllocateZeroPool ((PubKeyNumber
+ 1) * sizeof (UINT32
));
660 if (*NewPubKeyIndex
== NULL
) {
661 FreePool (*NewPubKeyStore
);
662 *NewPubKeyStore
= NULL
;
663 return EFI_OUT_OF_RESOURCES
;
667 for (PubKeyIndex
= 1; PubKeyIndex
<= PubKeyNumber
; PubKeyIndex
++) {
668 if (IsValidPubKeyIndex (PubKeyIndex
)) {
670 *NewPubKeyStore
+ CopiedKey
* EFI_CERT_TYPE_RSA2048_SIZE
,
671 PubKeyStore
+ (PubKeyIndex
- 1) * EFI_CERT_TYPE_RSA2048_SIZE
,
672 EFI_CERT_TYPE_RSA2048_SIZE
674 (*NewPubKeyIndex
)[PubKeyIndex
] = ++CopiedKey
;
682 Variable store garbage collection and reclaim operation.
684 If ReclaimPubKeyStore is FALSE, reclaim variable space by deleting the obsoleted varaibles.
685 If ReclaimPubKeyStore is TRUE, reclaim invalid key in public key database and update the PubKeyIndex
686 for all the count-based authenticate variable in NV storage.
688 @param[in] VariableBase Base address of variable store.
689 @param[out] LastVariableOffset Offset of last variable.
690 @param[in] IsVolatile The variable store is volatile or not;
691 if it is non-volatile, need FTW.
692 @param[in, out] UpdatingPtrTrack Pointer to updating variable pointer track structure.
693 @param[in] NewVariable Pointer to new variable.
694 @param[in] NewVariableSize New variable size.
695 @param[in] ReclaimPubKeyStore Reclaim for public key database or not.
697 @return EFI_SUCCESS Reclaim operation has finished successfully.
698 @return EFI_OUT_OF_RESOURCES No enough memory resources or variable space.
699 @return EFI_DEVICE_ERROR The public key database doesn't exist.
700 @return Others Unexpect error happened during reclaim operation.
705 IN EFI_PHYSICAL_ADDRESS VariableBase
,
706 OUT UINTN
*LastVariableOffset
,
707 IN BOOLEAN IsVolatile
,
708 IN OUT VARIABLE_POINTER_TRACK
*UpdatingPtrTrack
,
709 IN VARIABLE_HEADER
*NewVariable
,
710 IN UINTN NewVariableSize
,
711 IN BOOLEAN ReclaimPubKeyStore
714 VARIABLE_HEADER
*Variable
;
715 VARIABLE_HEADER
*AddedVariable
;
716 VARIABLE_HEADER
*NextVariable
;
717 VARIABLE_HEADER
*NextAddedVariable
;
718 VARIABLE_STORE_HEADER
*VariableStoreHeader
;
720 UINTN MaximumBufferSize
;
728 UINTN CommonVariableTotalSize
;
729 UINTN HwErrVariableTotalSize
;
730 UINT32
*NewPubKeyIndex
;
731 UINT8
*NewPubKeyStore
;
732 UINT32 NewPubKeySize
;
733 VARIABLE_HEADER
*PubKeyHeader
;
734 VARIABLE_HEADER
*UpdatingVariable
;
735 VARIABLE_HEADER
*UpdatingInDeletedTransition
;
737 UpdatingVariable
= NULL
;
738 UpdatingInDeletedTransition
= NULL
;
739 if (UpdatingPtrTrack
!= NULL
) {
740 UpdatingVariable
= UpdatingPtrTrack
->CurrPtr
;
741 UpdatingInDeletedTransition
= UpdatingPtrTrack
->InDeletedTransitionPtr
;
744 VariableStoreHeader
= (VARIABLE_STORE_HEADER
*) ((UINTN
) VariableBase
);
746 CommonVariableTotalSize
= 0;
747 HwErrVariableTotalSize
= 0;
748 NewPubKeyIndex
= NULL
;
749 NewPubKeyStore
= NULL
;
755 // Start Pointers for the variable.
757 Variable
= GetStartPointer (VariableStoreHeader
);
758 MaximumBufferSize
= sizeof (VARIABLE_STORE_HEADER
);
760 while (IsValidVariableHeader (Variable
, GetEndPointer (VariableStoreHeader
))) {
761 NextVariable
= GetNextVariablePtr (Variable
);
762 if ((Variable
->State
== VAR_ADDED
|| Variable
->State
== (VAR_IN_DELETED_TRANSITION
& VAR_ADDED
)) &&
763 Variable
!= UpdatingVariable
&&
764 Variable
!= UpdatingInDeletedTransition
766 VariableSize
= (UINTN
) NextVariable
- (UINTN
) Variable
;
767 MaximumBufferSize
+= VariableSize
;
770 Variable
= NextVariable
;
773 if (NewVariable
!= NULL
) {
775 // Add the new variable size.
777 MaximumBufferSize
+= NewVariableSize
;
781 // Reserve the 1 Bytes with Oxff to identify the
782 // end of the variable buffer.
784 MaximumBufferSize
+= 1;
785 ValidBuffer
= AllocatePool (MaximumBufferSize
);
786 if (ValidBuffer
== NULL
) {
787 return EFI_OUT_OF_RESOURCES
;
791 // For NV variable reclaim, don't allocate pool here and just use mNvVariableCache
792 // as the buffer to reduce SMRAM consumption for SMM variable driver.
794 MaximumBufferSize
= mNvVariableCache
->Size
;
795 ValidBuffer
= (UINT8
*) mNvVariableCache
;
798 SetMem (ValidBuffer
, MaximumBufferSize
, 0xff);
801 // Copy variable store header.
803 CopyMem (ValidBuffer
, VariableStoreHeader
, sizeof (VARIABLE_STORE_HEADER
));
804 CurrPtr
= (UINT8
*) GetStartPointer ((VARIABLE_STORE_HEADER
*) ValidBuffer
);
806 if (ReclaimPubKeyStore
) {
807 ASSERT (IsVolatile
== FALSE
);
809 // Trim the PubKeyStore and get new PubKeyIndex.
811 Status
= PubKeyStoreFilter (
818 if (EFI_ERROR (Status
)) {
821 ASSERT ((NewPubKeyIndex
!= NULL
) && (NewPubKeyStore
!= NULL
));
824 // Refresh the PubKeyIndex for all valid variables (ADDED and IN_DELETED_TRANSITION).
826 Variable
= GetStartPointer (VariableStoreHeader
);
827 while (IsValidVariableHeader (Variable
, GetEndPointer (VariableStoreHeader
))) {
828 NextVariable
= GetNextVariablePtr (Variable
);
829 if (Variable
->State
== VAR_ADDED
|| Variable
->State
== (VAR_IN_DELETED_TRANSITION
& VAR_ADDED
)) {
830 if ((StrCmp (GetVariableNamePtr (Variable
), AUTHVAR_KEYDB_NAME
) == 0) &&
831 (CompareGuid (&Variable
->VendorGuid
, &gEfiAuthenticatedVariableGuid
))) {
833 // Skip the public key database, it will be reinstalled later.
835 PubKeyHeader
= Variable
;
836 Variable
= NextVariable
;
840 VariableSize
= (UINTN
) NextVariable
- (UINTN
) Variable
;
841 CopyMem (CurrPtr
, (UINT8
*) Variable
, VariableSize
);
842 ((VARIABLE_HEADER
*) CurrPtr
)->PubKeyIndex
= NewPubKeyIndex
[Variable
->PubKeyIndex
];
843 CurrPtr
+= VariableSize
;
844 if ((Variable
->Attributes
& EFI_VARIABLE_HARDWARE_ERROR_RECORD
) == EFI_VARIABLE_HARDWARE_ERROR_RECORD
) {
845 HwErrVariableTotalSize
+= VariableSize
;
846 } else if ((Variable
->Attributes
& EFI_VARIABLE_HARDWARE_ERROR_RECORD
) != EFI_VARIABLE_HARDWARE_ERROR_RECORD
) {
847 CommonVariableTotalSize
+= VariableSize
;
850 Variable
= NextVariable
;
854 // Reinstall the new public key database.
856 ASSERT (PubKeyHeader
!= NULL
);
857 if (PubKeyHeader
== NULL
) {
858 Status
= EFI_DEVICE_ERROR
;
861 CopyMem (CurrPtr
, (UINT8
*) PubKeyHeader
, sizeof (VARIABLE_HEADER
));
862 Variable
= (VARIABLE_HEADER
*) CurrPtr
;
863 Variable
->DataSize
= NewPubKeySize
;
864 StrCpy (GetVariableNamePtr (Variable
), GetVariableNamePtr (PubKeyHeader
));
865 CopyMem (GetVariableDataPtr (Variable
), NewPubKeyStore
, NewPubKeySize
);
866 CurrPtr
= (UINT8
*) GetNextVariablePtr (Variable
);
867 CommonVariableTotalSize
+= (UINTN
) CurrPtr
- (UINTN
) Variable
;
870 // Reinstall all ADDED variables as long as they are not identical to Updating Variable.
872 Variable
= GetStartPointer (VariableStoreHeader
);
873 while (IsValidVariableHeader (Variable
, GetEndPointer (VariableStoreHeader
))) {
874 NextVariable
= GetNextVariablePtr (Variable
);
875 if (Variable
!= UpdatingVariable
&& Variable
->State
== VAR_ADDED
) {
876 VariableSize
= (UINTN
) NextVariable
- (UINTN
) Variable
;
877 CopyMem (CurrPtr
, (UINT8
*) Variable
, VariableSize
);
878 CurrPtr
+= VariableSize
;
879 if ((!IsVolatile
) && ((Variable
->Attributes
& EFI_VARIABLE_HARDWARE_ERROR_RECORD
) == EFI_VARIABLE_HARDWARE_ERROR_RECORD
)) {
880 HwErrVariableTotalSize
+= VariableSize
;
881 } else if ((!IsVolatile
) && ((Variable
->Attributes
& EFI_VARIABLE_HARDWARE_ERROR_RECORD
) != EFI_VARIABLE_HARDWARE_ERROR_RECORD
)) {
882 CommonVariableTotalSize
+= VariableSize
;
885 Variable
= NextVariable
;
889 // Reinstall all in delete transition variables.
891 Variable
= GetStartPointer (VariableStoreHeader
);
892 while (IsValidVariableHeader (Variable
, GetEndPointer (VariableStoreHeader
))) {
893 NextVariable
= GetNextVariablePtr (Variable
);
894 if (Variable
!= UpdatingVariable
&& Variable
!= UpdatingInDeletedTransition
&& Variable
->State
== (VAR_IN_DELETED_TRANSITION
& VAR_ADDED
)) {
897 // Buffer has cached all ADDED variable.
898 // Per IN_DELETED variable, we have to guarantee that
899 // no ADDED one in previous buffer.
903 AddedVariable
= GetStartPointer ((VARIABLE_STORE_HEADER
*) ValidBuffer
);
904 while (IsValidVariableHeader (AddedVariable
, GetEndPointer ((VARIABLE_STORE_HEADER
*) ValidBuffer
))) {
905 NextAddedVariable
= GetNextVariablePtr (AddedVariable
);
906 NameSize
= NameSizeOfVariable (AddedVariable
);
907 if (CompareGuid (&AddedVariable
->VendorGuid
, &Variable
->VendorGuid
) &&
908 NameSize
== NameSizeOfVariable (Variable
)
910 Point0
= (VOID
*) GetVariableNamePtr (AddedVariable
);
911 Point1
= (VOID
*) GetVariableNamePtr (Variable
);
912 if (CompareMem (Point0
, Point1
, NameSize
) == 0) {
917 AddedVariable
= NextAddedVariable
;
921 // Promote VAR_IN_DELETED_TRANSITION to VAR_ADDED.
923 VariableSize
= (UINTN
) NextVariable
- (UINTN
) Variable
;
924 CopyMem (CurrPtr
, (UINT8
*) Variable
, VariableSize
);
925 ((VARIABLE_HEADER
*) CurrPtr
)->State
= VAR_ADDED
;
926 CurrPtr
+= VariableSize
;
927 if ((!IsVolatile
) && ((Variable
->Attributes
& EFI_VARIABLE_HARDWARE_ERROR_RECORD
) == EFI_VARIABLE_HARDWARE_ERROR_RECORD
)) {
928 HwErrVariableTotalSize
+= VariableSize
;
929 } else if ((!IsVolatile
) && ((Variable
->Attributes
& EFI_VARIABLE_HARDWARE_ERROR_RECORD
) != EFI_VARIABLE_HARDWARE_ERROR_RECORD
)) {
930 CommonVariableTotalSize
+= VariableSize
;
935 Variable
= NextVariable
;
939 // Install the new variable if it is not NULL.
941 if (NewVariable
!= NULL
) {
942 if ((UINTN
) (CurrPtr
- ValidBuffer
) + NewVariableSize
> VariableStoreHeader
->Size
) {
944 // No enough space to store the new variable.
946 Status
= EFI_OUT_OF_RESOURCES
;
950 if ((NewVariable
->Attributes
& EFI_VARIABLE_HARDWARE_ERROR_RECORD
) == EFI_VARIABLE_HARDWARE_ERROR_RECORD
) {
951 HwErrVariableTotalSize
+= NewVariableSize
;
952 } else if ((NewVariable
->Attributes
& EFI_VARIABLE_HARDWARE_ERROR_RECORD
) != EFI_VARIABLE_HARDWARE_ERROR_RECORD
) {
953 CommonVariableTotalSize
+= NewVariableSize
;
955 if ((HwErrVariableTotalSize
> PcdGet32 (PcdHwErrStorageSize
)) ||
956 (CommonVariableTotalSize
> VariableStoreHeader
->Size
- sizeof (VARIABLE_STORE_HEADER
) - PcdGet32 (PcdHwErrStorageSize
))) {
958 // No enough space to store the new variable by NV or NV+HR attribute.
960 Status
= EFI_OUT_OF_RESOURCES
;
965 CopyMem (CurrPtr
, (UINT8
*) NewVariable
, NewVariableSize
);
966 ((VARIABLE_HEADER
*) CurrPtr
)->State
= VAR_ADDED
;
967 if (UpdatingVariable
!= NULL
) {
968 UpdatingPtrTrack
->CurrPtr
= (VARIABLE_HEADER
*)((UINTN
)UpdatingPtrTrack
->StartPtr
+ ((UINTN
)CurrPtr
- (UINTN
)GetStartPointer ((VARIABLE_STORE_HEADER
*) ValidBuffer
)));
969 UpdatingPtrTrack
->InDeletedTransitionPtr
= NULL
;
971 CurrPtr
+= NewVariableSize
;
977 // If volatile variable store, just copy valid buffer.
979 SetMem ((UINT8
*) (UINTN
) VariableBase
, VariableStoreHeader
->Size
, 0xff);
980 CopyMem ((UINT8
*) (UINTN
) VariableBase
, ValidBuffer
, (UINTN
) (CurrPtr
- ValidBuffer
));
981 *LastVariableOffset
= (UINTN
) (CurrPtr
- ValidBuffer
);
982 Status
= EFI_SUCCESS
;
985 // If non-volatile variable store, perform FTW here.
987 Status
= FtwVariableSpace (
989 (VARIABLE_STORE_HEADER
*) ValidBuffer
991 if (!EFI_ERROR (Status
)) {
992 *LastVariableOffset
= (UINTN
) (CurrPtr
- ValidBuffer
);
993 mVariableModuleGlobal
->HwErrVariableTotalSize
= HwErrVariableTotalSize
;
994 mVariableModuleGlobal
->CommonVariableTotalSize
= CommonVariableTotalSize
;
996 NextVariable
= GetStartPointer ((VARIABLE_STORE_HEADER
*)(UINTN
)VariableBase
);
997 while (IsValidVariableHeader (NextVariable
, GetEndPointer ((VARIABLE_STORE_HEADER
*)(UINTN
)VariableBase
))) {
998 VariableSize
= NextVariable
->NameSize
+ NextVariable
->DataSize
+ sizeof (VARIABLE_HEADER
);
999 if ((Variable
->Attributes
& EFI_VARIABLE_HARDWARE_ERROR_RECORD
) == EFI_VARIABLE_HARDWARE_ERROR_RECORD
) {
1000 mVariableModuleGlobal
->HwErrVariableTotalSize
+= HEADER_ALIGN (VariableSize
);
1001 } else if ((Variable
->Attributes
& EFI_VARIABLE_HARDWARE_ERROR_RECORD
) != EFI_VARIABLE_HARDWARE_ERROR_RECORD
) {
1002 mVariableModuleGlobal
->CommonVariableTotalSize
+= HEADER_ALIGN (VariableSize
);
1005 NextVariable
= GetNextVariablePtr (NextVariable
);
1007 *LastVariableOffset
= (UINTN
) NextVariable
- (UINTN
) VariableBase
;
1013 FreePool (ValidBuffer
);
1016 // For NV variable reclaim, we use mNvVariableCache as the buffer, so copy the data back.
1018 CopyMem (mNvVariableCache
, (UINT8
*)(UINTN
)VariableBase
, VariableStoreHeader
->Size
);
1020 if (NewPubKeyStore
!= NULL
) {
1021 FreePool (NewPubKeyStore
);
1024 if (NewPubKeyIndex
!= NULL
) {
1025 FreePool (NewPubKeyIndex
);
1033 Find the variable in the specified variable store.
1035 @param[in] VariableName Name of the variable to be found
1036 @param[in] VendorGuid Vendor GUID to be found.
1037 @param[in] IgnoreRtCheck Ignore EFI_VARIABLE_RUNTIME_ACCESS attribute
1038 check at runtime when searching variable.
1039 @param[in, out] PtrTrack Variable Track Pointer structure that contains Variable Information.
1041 @retval EFI_SUCCESS Variable found successfully
1042 @retval EFI_NOT_FOUND Variable not found
1046 IN CHAR16
*VariableName
,
1047 IN EFI_GUID
*VendorGuid
,
1048 IN BOOLEAN IgnoreRtCheck
,
1049 IN OUT VARIABLE_POINTER_TRACK
*PtrTrack
1052 VARIABLE_HEADER
*InDeletedVariable
;
1055 PtrTrack
->InDeletedTransitionPtr
= NULL
;
1058 // Find the variable by walk through HOB, volatile and non-volatile variable store.
1060 InDeletedVariable
= NULL
;
1062 for ( PtrTrack
->CurrPtr
= PtrTrack
->StartPtr
1063 ; IsValidVariableHeader (PtrTrack
->CurrPtr
, PtrTrack
->EndPtr
)
1064 ; PtrTrack
->CurrPtr
= GetNextVariablePtr (PtrTrack
->CurrPtr
)
1066 if (PtrTrack
->CurrPtr
->State
== VAR_ADDED
||
1067 PtrTrack
->CurrPtr
->State
== (VAR_IN_DELETED_TRANSITION
& VAR_ADDED
)
1069 if (IgnoreRtCheck
|| !AtRuntime () || ((PtrTrack
->CurrPtr
->Attributes
& EFI_VARIABLE_RUNTIME_ACCESS
) != 0)) {
1070 if (VariableName
[0] == 0) {
1071 if (PtrTrack
->CurrPtr
->State
== (VAR_IN_DELETED_TRANSITION
& VAR_ADDED
)) {
1072 InDeletedVariable
= PtrTrack
->CurrPtr
;
1074 PtrTrack
->InDeletedTransitionPtr
= InDeletedVariable
;
1078 if (CompareGuid (VendorGuid
, &PtrTrack
->CurrPtr
->VendorGuid
)) {
1079 Point
= (VOID
*) GetVariableNamePtr (PtrTrack
->CurrPtr
);
1081 ASSERT (NameSizeOfVariable (PtrTrack
->CurrPtr
) != 0);
1082 if (CompareMem (VariableName
, Point
, NameSizeOfVariable (PtrTrack
->CurrPtr
)) == 0) {
1083 if (PtrTrack
->CurrPtr
->State
== (VAR_IN_DELETED_TRANSITION
& VAR_ADDED
)) {
1084 InDeletedVariable
= PtrTrack
->CurrPtr
;
1086 PtrTrack
->InDeletedTransitionPtr
= InDeletedVariable
;
1096 PtrTrack
->CurrPtr
= InDeletedVariable
;
1097 return (PtrTrack
->CurrPtr
== NULL
) ? EFI_NOT_FOUND
: EFI_SUCCESS
;
1102 Finds variable in storage blocks of volatile and non-volatile storage areas.
1104 This code finds variable in storage blocks of volatile and non-volatile storage areas.
1105 If VariableName is an empty string, then we just return the first
1106 qualified variable without comparing VariableName and VendorGuid.
1107 If IgnoreRtCheck is TRUE, then we ignore the EFI_VARIABLE_RUNTIME_ACCESS attribute check
1108 at runtime when searching existing variable, only VariableName and VendorGuid are compared.
1109 Otherwise, variables without EFI_VARIABLE_RUNTIME_ACCESS are not visible at runtime.
1111 @param[in] VariableName Name of the variable to be found.
1112 @param[in] VendorGuid Vendor GUID to be found.
1113 @param[out] PtrTrack VARIABLE_POINTER_TRACK structure for output,
1114 including the range searched and the target position.
1115 @param[in] Global Pointer to VARIABLE_GLOBAL structure, including
1116 base of volatile variable storage area, base of
1117 NV variable storage area, and a lock.
1118 @param[in] IgnoreRtCheck Ignore EFI_VARIABLE_RUNTIME_ACCESS attribute
1119 check at runtime when searching variable.
1121 @retval EFI_INVALID_PARAMETER If VariableName is not an empty string, while
1123 @retval EFI_SUCCESS Variable successfully found.
1124 @retval EFI_NOT_FOUND Variable not found
1129 IN CHAR16
*VariableName
,
1130 IN EFI_GUID
*VendorGuid
,
1131 OUT VARIABLE_POINTER_TRACK
*PtrTrack
,
1132 IN VARIABLE_GLOBAL
*Global
,
1133 IN BOOLEAN IgnoreRtCheck
1137 VARIABLE_STORE_HEADER
*VariableStoreHeader
[VariableStoreTypeMax
];
1138 VARIABLE_STORE_TYPE Type
;
1140 if (VariableName
[0] != 0 && VendorGuid
== NULL
) {
1141 return EFI_INVALID_PARAMETER
;
1145 // 0: Volatile, 1: HOB, 2: Non-Volatile.
1146 // The index and attributes mapping must be kept in this order as RuntimeServiceGetNextVariableName
1147 // make use of this mapping to implement search algorithm.
1149 VariableStoreHeader
[VariableStoreTypeVolatile
] = (VARIABLE_STORE_HEADER
*) (UINTN
) Global
->VolatileVariableBase
;
1150 VariableStoreHeader
[VariableStoreTypeHob
] = (VARIABLE_STORE_HEADER
*) (UINTN
) Global
->HobVariableBase
;
1151 VariableStoreHeader
[VariableStoreTypeNv
] = mNvVariableCache
;
1154 // Find the variable by walk through HOB, volatile and non-volatile variable store.
1156 for (Type
= (VARIABLE_STORE_TYPE
) 0; Type
< VariableStoreTypeMax
; Type
++) {
1157 if (VariableStoreHeader
[Type
] == NULL
) {
1161 PtrTrack
->StartPtr
= GetStartPointer (VariableStoreHeader
[Type
]);
1162 PtrTrack
->EndPtr
= GetEndPointer (VariableStoreHeader
[Type
]);
1163 PtrTrack
->Volatile
= (BOOLEAN
) (Type
== VariableStoreTypeVolatile
);
1165 Status
= FindVariableEx (VariableName
, VendorGuid
, IgnoreRtCheck
, PtrTrack
);
1166 if (!EFI_ERROR (Status
)) {
1170 return EFI_NOT_FOUND
;
1174 Get index from supported language codes according to language string.
1176 This code is used to get corresponding index in supported language codes. It can handle
1177 RFC4646 and ISO639 language tags.
1178 In ISO639 language tags, take 3-characters as a delimitation to find matched string and calculate the index.
1179 In RFC4646 language tags, take semicolon as a delimitation to find matched string and calculate the index.
1182 SupportedLang = "engfraengfra"
1184 Iso639Language = TRUE
1185 The return value is "0".
1187 SupportedLang = "en;fr;en-US;fr-FR"
1189 Iso639Language = FALSE
1190 The return value is "3".
1192 @param SupportedLang Platform supported language codes.
1193 @param Lang Configured language.
1194 @param Iso639Language A bool value to signify if the handler is operated on ISO639 or RFC4646.
1196 @retval The index of language in the language codes.
1200 GetIndexFromSupportedLangCodes(
1201 IN CHAR8
*SupportedLang
,
1203 IN BOOLEAN Iso639Language
1207 UINTN CompareLength
;
1208 UINTN LanguageLength
;
1210 if (Iso639Language
) {
1211 CompareLength
= ISO_639_2_ENTRY_SIZE
;
1212 for (Index
= 0; Index
< AsciiStrLen (SupportedLang
); Index
+= CompareLength
) {
1213 if (AsciiStrnCmp (Lang
, SupportedLang
+ Index
, CompareLength
) == 0) {
1215 // Successfully find the index of Lang string in SupportedLang string.
1217 Index
= Index
/ CompareLength
;
1225 // Compare RFC4646 language code
1228 for (LanguageLength
= 0; Lang
[LanguageLength
] != '\0'; LanguageLength
++);
1230 for (Index
= 0; *SupportedLang
!= '\0'; Index
++, SupportedLang
+= CompareLength
) {
1232 // Skip ';' characters in SupportedLang
1234 for (; *SupportedLang
!= '\0' && *SupportedLang
== ';'; SupportedLang
++);
1236 // Determine the length of the next language code in SupportedLang
1238 for (CompareLength
= 0; SupportedLang
[CompareLength
] != '\0' && SupportedLang
[CompareLength
] != ';'; CompareLength
++);
1240 if ((CompareLength
== LanguageLength
) &&
1241 (AsciiStrnCmp (Lang
, SupportedLang
, CompareLength
) == 0)) {
1243 // Successfully find the index of Lang string in SupportedLang string.
1254 Get language string from supported language codes according to index.
1256 This code is used to get corresponding language strings in supported language codes. It can handle
1257 RFC4646 and ISO639 language tags.
1258 In ISO639 language tags, take 3-characters as a delimitation. Find language string according to the index.
1259 In RFC4646 language tags, take semicolon as a delimitation. Find language string according to the index.
1262 SupportedLang = "engfraengfra"
1264 Iso639Language = TRUE
1265 The return value is "fra".
1267 SupportedLang = "en;fr;en-US;fr-FR"
1269 Iso639Language = FALSE
1270 The return value is "fr".
1272 @param SupportedLang Platform supported language codes.
1273 @param Index The index in supported language codes.
1274 @param Iso639Language A bool value to signify if the handler is operated on ISO639 or RFC4646.
1276 @retval The language string in the language codes.
1280 GetLangFromSupportedLangCodes (
1281 IN CHAR8
*SupportedLang
,
1283 IN BOOLEAN Iso639Language
1287 UINTN CompareLength
;
1291 Supported
= SupportedLang
;
1292 if (Iso639Language
) {
1294 // According to the index of Lang string in SupportedLang string to get the language.
1295 // This code will be invoked in RUNTIME, therefore there is not a memory allocate/free operation.
1296 // In driver entry, it pre-allocates a runtime attribute memory to accommodate this string.
1298 CompareLength
= ISO_639_2_ENTRY_SIZE
;
1299 mVariableModuleGlobal
->Lang
[CompareLength
] = '\0';
1300 return CopyMem (mVariableModuleGlobal
->Lang
, SupportedLang
+ Index
* CompareLength
, CompareLength
);
1305 // Take semicolon as delimitation, sequentially traverse supported language codes.
1307 for (CompareLength
= 0; *Supported
!= ';' && *Supported
!= '\0'; CompareLength
++) {
1310 if ((*Supported
== '\0') && (SubIndex
!= Index
)) {
1312 // Have completed the traverse, but not find corrsponding string.
1313 // This case is not allowed to happen.
1318 if (SubIndex
== Index
) {
1320 // According to the index of Lang string in SupportedLang string to get the language.
1321 // As this code will be invoked in RUNTIME, therefore there is not memory allocate/free operation.
1322 // In driver entry, it pre-allocates a runtime attribute memory to accommodate this string.
1324 mVariableModuleGlobal
->PlatformLang
[CompareLength
] = '\0';
1325 return CopyMem (mVariableModuleGlobal
->PlatformLang
, Supported
- CompareLength
, CompareLength
);
1330 // Skip ';' characters in Supported
1332 for (; *Supported
!= '\0' && *Supported
== ';'; Supported
++);
1338 Returns a pointer to an allocated buffer that contains the best matching language
1339 from a set of supported languages.
1341 This function supports both ISO 639-2 and RFC 4646 language codes, but language
1342 code types may not be mixed in a single call to this function. This function
1343 supports a variable argument list that allows the caller to pass in a prioritized
1344 list of language codes to test against all the language codes in SupportedLanguages.
1346 If SupportedLanguages is NULL, then ASSERT().
1348 @param[in] SupportedLanguages A pointer to a Null-terminated ASCII string that
1349 contains a set of language codes in the format
1350 specified by Iso639Language.
1351 @param[in] Iso639Language If TRUE, then all language codes are assumed to be
1352 in ISO 639-2 format. If FALSE, then all language
1353 codes are assumed to be in RFC 4646 language format
1354 @param[in] ... A variable argument list that contains pointers to
1355 Null-terminated ASCII strings that contain one or more
1356 language codes in the format specified by Iso639Language.
1357 The first language code from each of these language
1358 code lists is used to determine if it is an exact or
1359 close match to any of the language codes in
1360 SupportedLanguages. Close matches only apply to RFC 4646
1361 language codes, and the matching algorithm from RFC 4647
1362 is used to determine if a close match is present. If
1363 an exact or close match is found, then the matching
1364 language code from SupportedLanguages is returned. If
1365 no matches are found, then the next variable argument
1366 parameter is evaluated. The variable argument list
1367 is terminated by a NULL.
1369 @retval NULL The best matching language could not be found in SupportedLanguages.
1370 @retval NULL There are not enough resources available to return the best matching
1372 @retval Other A pointer to a Null-terminated ASCII string that is the best matching
1373 language in SupportedLanguages.
1378 VariableGetBestLanguage (
1379 IN CONST CHAR8
*SupportedLanguages
,
1380 IN BOOLEAN Iso639Language
,
1386 UINTN CompareLength
;
1387 UINTN LanguageLength
;
1388 CONST CHAR8
*Supported
;
1391 if (SupportedLanguages
== NULL
) {
1395 VA_START (Args
, Iso639Language
);
1396 while ((Language
= VA_ARG (Args
, CHAR8
*)) != NULL
) {
1398 // Default to ISO 639-2 mode
1401 LanguageLength
= MIN (3, AsciiStrLen (Language
));
1404 // If in RFC 4646 mode, then determine the length of the first RFC 4646 language code in Language
1406 if (!Iso639Language
) {
1407 for (LanguageLength
= 0; Language
[LanguageLength
] != 0 && Language
[LanguageLength
] != ';'; LanguageLength
++);
1411 // Trim back the length of Language used until it is empty
1413 while (LanguageLength
> 0) {
1415 // Loop through all language codes in SupportedLanguages
1417 for (Supported
= SupportedLanguages
; *Supported
!= '\0'; Supported
+= CompareLength
) {
1419 // In RFC 4646 mode, then Loop through all language codes in SupportedLanguages
1421 if (!Iso639Language
) {
1423 // Skip ';' characters in Supported
1425 for (; *Supported
!= '\0' && *Supported
== ';'; Supported
++);
1427 // Determine the length of the next language code in Supported
1429 for (CompareLength
= 0; Supported
[CompareLength
] != 0 && Supported
[CompareLength
] != ';'; CompareLength
++);
1431 // If Language is longer than the Supported, then skip to the next language
1433 if (LanguageLength
> CompareLength
) {
1438 // See if the first LanguageLength characters in Supported match Language
1440 if (AsciiStrnCmp (Supported
, Language
, LanguageLength
) == 0) {
1443 Buffer
= Iso639Language
? mVariableModuleGlobal
->Lang
: mVariableModuleGlobal
->PlatformLang
;
1444 Buffer
[CompareLength
] = '\0';
1445 return CopyMem (Buffer
, Supported
, CompareLength
);
1449 if (Iso639Language
) {
1451 // If ISO 639 mode, then each language can only be tested once
1456 // If RFC 4646 mode, then trim Language from the right to the next '-' character
1458 for (LanguageLength
--; LanguageLength
> 0 && Language
[LanguageLength
] != '-'; LanguageLength
--);
1465 // No matches were found
1471 This function is to check if the remaining variable space is enough to set
1472 all Variables from argument list successfully. The purpose of the check
1473 is to keep the consistency of the Variables to be in variable storage.
1475 Note: Variables are assumed to be in same storage.
1476 The set sequence of Variables will be same with the sequence of VariableEntry from argument list,
1477 so follow the argument sequence to check the Variables.
1479 @param[in] Attributes Variable attributes for Variable entries.
1480 @param ... The variable argument list with type VARIABLE_ENTRY_CONSISTENCY *.
1481 A NULL terminates the list. The VariableSize of
1482 VARIABLE_ENTRY_CONSISTENCY is the variable data size as input.
1483 It will be changed to variable total size as output.
1485 @retval TRUE Have enough variable space to set the Variables successfully.
1486 @retval FALSE No enough variable space to set the Variables successfully.
1491 CheckRemainingSpaceForConsistency (
1492 IN UINT32 Attributes
,
1498 VARIABLE_ENTRY_CONSISTENCY
*VariableEntry
;
1499 UINT64 MaximumVariableStorageSize
;
1500 UINT64 RemainingVariableStorageSize
;
1501 UINT64 MaximumVariableSize
;
1502 UINTN TotalNeededSize
;
1503 UINTN OriginalVarSize
;
1504 VARIABLE_STORE_HEADER
*VariableStoreHeader
;
1505 VARIABLE_POINTER_TRACK VariablePtrTrack
;
1506 VARIABLE_HEADER
*NextVariable
;
1511 // Non-Volatile related.
1513 VariableStoreHeader
= mNvVariableCache
;
1515 Status
= VariableServiceQueryVariableInfoInternal (
1517 &MaximumVariableStorageSize
,
1518 &RemainingVariableStorageSize
,
1519 &MaximumVariableSize
1521 ASSERT_EFI_ERROR (Status
);
1523 TotalNeededSize
= 0;
1524 VA_START (Args
, Attributes
);
1525 VariableEntry
= VA_ARG (Args
, VARIABLE_ENTRY_CONSISTENCY
*);
1526 while (VariableEntry
!= NULL
) {
1528 // Calculate variable total size.
1530 VarNameSize
= StrSize (VariableEntry
->Name
);
1531 VarNameSize
+= GET_PAD_SIZE (VarNameSize
);
1532 VarDataSize
= VariableEntry
->VariableSize
;
1533 VarDataSize
+= GET_PAD_SIZE (VarDataSize
);
1534 VariableEntry
->VariableSize
= HEADER_ALIGN (sizeof (VARIABLE_HEADER
) + VarNameSize
+ VarDataSize
);
1536 TotalNeededSize
+= VariableEntry
->VariableSize
;
1537 VariableEntry
= VA_ARG (Args
, VARIABLE_ENTRY_CONSISTENCY
*);
1541 if (RemainingVariableStorageSize
>= TotalNeededSize
) {
1543 // Already have enough space.
1546 } else if (AtRuntime ()) {
1548 // At runtime, no reclaim.
1549 // The original variable space of Variables can't be reused.
1554 VA_START (Args
, Attributes
);
1555 VariableEntry
= VA_ARG (Args
, VARIABLE_ENTRY_CONSISTENCY
*);
1556 while (VariableEntry
!= NULL
) {
1558 // Check if Variable[Index] has been present and get its size.
1560 OriginalVarSize
= 0;
1561 VariablePtrTrack
.StartPtr
= GetStartPointer (VariableStoreHeader
);
1562 VariablePtrTrack
.EndPtr
= GetEndPointer (VariableStoreHeader
);
1563 Status
= FindVariableEx (
1564 VariableEntry
->Name
,
1565 VariableEntry
->Guid
,
1569 if (!EFI_ERROR (Status
)) {
1571 // Get size of Variable[Index].
1573 NextVariable
= GetNextVariablePtr (VariablePtrTrack
.CurrPtr
);
1574 OriginalVarSize
= (UINTN
) NextVariable
- (UINTN
) VariablePtrTrack
.CurrPtr
;
1576 // Add the original size of Variable[Index] to remaining variable storage size.
1578 RemainingVariableStorageSize
+= OriginalVarSize
;
1580 if (VariableEntry
->VariableSize
> RemainingVariableStorageSize
) {
1582 // No enough space for Variable[Index].
1588 // Sub the (new) size of Variable[Index] from remaining variable storage size.
1590 RemainingVariableStorageSize
-= VariableEntry
->VariableSize
;
1591 VariableEntry
= VA_ARG (Args
, VARIABLE_ENTRY_CONSISTENCY
*);
1599 Hook the operations in PlatformLangCodes, LangCodes, PlatformLang and Lang.
1601 When setting Lang/LangCodes, simultaneously update PlatformLang/PlatformLangCodes.
1603 According to UEFI spec, PlatformLangCodes/LangCodes are only set once in firmware initialization,
1604 and are read-only. Therefore, in variable driver, only store the original value for other use.
1606 @param[in] VariableName Name of variable.
1608 @param[in] Data Variable data.
1610 @param[in] DataSize Size of data. 0 means delete.
1612 @retval EFI_SUCCESS The update operation is successful or ignored.
1613 @retval EFI_WRITE_PROTECTED Update PlatformLangCodes/LangCodes at runtime.
1614 @retval EFI_OUT_OF_RESOURCES No enough variable space to do the update operation.
1615 @retval Others Other errors happened during the update operation.
1619 AutoUpdateLangVariable (
1620 IN CHAR16
*VariableName
,
1626 CHAR8
*BestPlatformLang
;
1630 VARIABLE_POINTER_TRACK Variable
;
1631 BOOLEAN SetLanguageCodes
;
1632 VARIABLE_ENTRY_CONSISTENCY VariableEntry
[2];
1635 // Don't do updates for delete operation
1637 if (DataSize
== 0) {
1641 SetLanguageCodes
= FALSE
;
1643 if (StrCmp (VariableName
, EFI_PLATFORM_LANG_CODES_VARIABLE_NAME
) == 0) {
1645 // PlatformLangCodes is a volatile variable, so it can not be updated at runtime.
1648 return EFI_WRITE_PROTECTED
;
1651 SetLanguageCodes
= TRUE
;
1654 // According to UEFI spec, PlatformLangCodes is only set once in firmware initialization, and is read-only
1655 // Therefore, in variable driver, only store the original value for other use.
1657 if (mVariableModuleGlobal
->PlatformLangCodes
!= NULL
) {
1658 FreePool (mVariableModuleGlobal
->PlatformLangCodes
);
1660 mVariableModuleGlobal
->PlatformLangCodes
= AllocateRuntimeCopyPool (DataSize
, Data
);
1661 ASSERT (mVariableModuleGlobal
->PlatformLangCodes
!= NULL
);
1664 // PlatformLang holds a single language from PlatformLangCodes,
1665 // so the size of PlatformLangCodes is enough for the PlatformLang.
1667 if (mVariableModuleGlobal
->PlatformLang
!= NULL
) {
1668 FreePool (mVariableModuleGlobal
->PlatformLang
);
1670 mVariableModuleGlobal
->PlatformLang
= AllocateRuntimePool (DataSize
);
1671 ASSERT (mVariableModuleGlobal
->PlatformLang
!= NULL
);
1673 } else if (StrCmp (VariableName
, EFI_LANG_CODES_VARIABLE_NAME
) == 0) {
1675 // LangCodes is a volatile variable, so it can not be updated at runtime.
1678 return EFI_WRITE_PROTECTED
;
1681 SetLanguageCodes
= TRUE
;
1684 // According to UEFI spec, LangCodes is only set once in firmware initialization, and is read-only
1685 // Therefore, in variable driver, only store the original value for other use.
1687 if (mVariableModuleGlobal
->LangCodes
!= NULL
) {
1688 FreePool (mVariableModuleGlobal
->LangCodes
);
1690 mVariableModuleGlobal
->LangCodes
= AllocateRuntimeCopyPool (DataSize
, Data
);
1691 ASSERT (mVariableModuleGlobal
->LangCodes
!= NULL
);
1694 if (SetLanguageCodes
1695 && (mVariableModuleGlobal
->PlatformLangCodes
!= NULL
)
1696 && (mVariableModuleGlobal
->LangCodes
!= NULL
)) {
1698 // Update Lang if PlatformLang is already set
1699 // Update PlatformLang if Lang is already set
1701 Status
= FindVariable (EFI_PLATFORM_LANG_VARIABLE_NAME
, &gEfiGlobalVariableGuid
, &Variable
, &mVariableModuleGlobal
->VariableGlobal
, FALSE
);
1702 if (!EFI_ERROR (Status
)) {
1706 VariableName
= EFI_PLATFORM_LANG_VARIABLE_NAME
;
1707 Data
= GetVariableDataPtr (Variable
.CurrPtr
);
1708 DataSize
= Variable
.CurrPtr
->DataSize
;
1710 Status
= FindVariable (EFI_LANG_VARIABLE_NAME
, &gEfiGlobalVariableGuid
, &Variable
, &mVariableModuleGlobal
->VariableGlobal
, FALSE
);
1711 if (!EFI_ERROR (Status
)) {
1713 // Update PlatformLang
1715 VariableName
= EFI_LANG_VARIABLE_NAME
;
1716 Data
= GetVariableDataPtr (Variable
.CurrPtr
);
1717 DataSize
= Variable
.CurrPtr
->DataSize
;
1720 // Neither PlatformLang nor Lang is set, directly return
1727 Status
= EFI_SUCCESS
;
1730 // According to UEFI spec, "Lang" and "PlatformLang" is NV|BS|RT attributions.
1732 Attributes
= EFI_VARIABLE_NON_VOLATILE
| EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_RUNTIME_ACCESS
;
1734 if (StrCmp (VariableName
, EFI_PLATFORM_LANG_VARIABLE_NAME
) == 0) {
1736 // Update Lang when PlatformLangCodes/LangCodes were set.
1738 if ((mVariableModuleGlobal
->PlatformLangCodes
!= NULL
) && (mVariableModuleGlobal
->LangCodes
!= NULL
)) {
1740 // When setting PlatformLang, firstly get most matched language string from supported language codes.
1742 BestPlatformLang
= VariableGetBestLanguage (mVariableModuleGlobal
->PlatformLangCodes
, FALSE
, Data
, NULL
);
1743 if (BestPlatformLang
!= NULL
) {
1745 // Get the corresponding index in language codes.
1747 Index
= GetIndexFromSupportedLangCodes (mVariableModuleGlobal
->PlatformLangCodes
, BestPlatformLang
, FALSE
);
1750 // Get the corresponding ISO639 language tag according to RFC4646 language tag.
1752 BestLang
= GetLangFromSupportedLangCodes (mVariableModuleGlobal
->LangCodes
, Index
, TRUE
);
1755 // Check the variable space for both Lang and PlatformLang variable.
1757 VariableEntry
[0].VariableSize
= ISO_639_2_ENTRY_SIZE
+ 1;
1758 VariableEntry
[0].Guid
= &gEfiGlobalVariableGuid
;
1759 VariableEntry
[0].Name
= EFI_LANG_VARIABLE_NAME
;
1761 VariableEntry
[1].VariableSize
= AsciiStrSize (BestPlatformLang
);
1762 VariableEntry
[1].Guid
= &gEfiGlobalVariableGuid
;
1763 VariableEntry
[1].Name
= EFI_PLATFORM_LANG_VARIABLE_NAME
;
1764 if (!CheckRemainingSpaceForConsistency (VARIABLE_ATTRIBUTE_NV_BS_RT
, &VariableEntry
[0], &VariableEntry
[1], NULL
)) {
1766 // No enough variable space to set both Lang and PlatformLang successfully.
1768 Status
= EFI_OUT_OF_RESOURCES
;
1771 // Successfully convert PlatformLang to Lang, and set the BestLang value into Lang variable simultaneously.
1773 FindVariable (EFI_LANG_VARIABLE_NAME
, &gEfiGlobalVariableGuid
, &Variable
, &mVariableModuleGlobal
->VariableGlobal
, FALSE
);
1775 Status
= UpdateVariable (EFI_LANG_VARIABLE_NAME
, &gEfiGlobalVariableGuid
, BestLang
,
1776 ISO_639_2_ENTRY_SIZE
+ 1, Attributes
, 0, 0, &Variable
, NULL
);
1779 DEBUG ((EFI_D_INFO
, "Variable Driver Auto Update PlatformLang, PlatformLang:%a, Lang:%a Status: %r\n", BestPlatformLang
, BestLang
, Status
));
1783 } else if (StrCmp (VariableName
, EFI_LANG_VARIABLE_NAME
) == 0) {
1785 // Update PlatformLang when PlatformLangCodes/LangCodes were set.
1787 if ((mVariableModuleGlobal
->PlatformLangCodes
!= NULL
) && (mVariableModuleGlobal
->LangCodes
!= NULL
)) {
1789 // When setting Lang, firstly get most matched language string from supported language codes.
1791 BestLang
= VariableGetBestLanguage (mVariableModuleGlobal
->LangCodes
, TRUE
, Data
, NULL
);
1792 if (BestLang
!= NULL
) {
1794 // Get the corresponding index in language codes.
1796 Index
= GetIndexFromSupportedLangCodes (mVariableModuleGlobal
->LangCodes
, BestLang
, TRUE
);
1799 // Get the corresponding RFC4646 language tag according to ISO639 language tag.
1801 BestPlatformLang
= GetLangFromSupportedLangCodes (mVariableModuleGlobal
->PlatformLangCodes
, Index
, FALSE
);
1804 // Check the variable space for both PlatformLang and Lang variable.
1806 VariableEntry
[0].VariableSize
= AsciiStrSize (BestPlatformLang
);
1807 VariableEntry
[0].Guid
= &gEfiGlobalVariableGuid
;
1808 VariableEntry
[0].Name
= EFI_PLATFORM_LANG_VARIABLE_NAME
;
1810 VariableEntry
[1].VariableSize
= ISO_639_2_ENTRY_SIZE
+ 1;
1811 VariableEntry
[1].Guid
= &gEfiGlobalVariableGuid
;
1812 VariableEntry
[1].Name
= EFI_LANG_VARIABLE_NAME
;
1813 if (!CheckRemainingSpaceForConsistency (VARIABLE_ATTRIBUTE_NV_BS_RT
, &VariableEntry
[0], &VariableEntry
[1], NULL
)) {
1815 // No enough variable space to set both PlatformLang and Lang successfully.
1817 Status
= EFI_OUT_OF_RESOURCES
;
1820 // Successfully convert Lang to PlatformLang, and set the BestPlatformLang value into PlatformLang variable simultaneously.
1822 FindVariable (EFI_PLATFORM_LANG_VARIABLE_NAME
, &gEfiGlobalVariableGuid
, &Variable
, &mVariableModuleGlobal
->VariableGlobal
, FALSE
);
1824 Status
= UpdateVariable (EFI_PLATFORM_LANG_VARIABLE_NAME
, &gEfiGlobalVariableGuid
, BestPlatformLang
,
1825 AsciiStrSize (BestPlatformLang
), Attributes
, 0, 0, &Variable
, NULL
);
1828 DEBUG ((EFI_D_INFO
, "Variable Driver Auto Update Lang, Lang:%a, PlatformLang:%a Status: %r\n", BestLang
, BestPlatformLang
, Status
));
1833 if (SetLanguageCodes
) {
1835 // Continue to set PlatformLangCodes or LangCodes.
1844 Update the variable region with Variable information. If EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS is set,
1845 index of associated public key is needed.
1847 @param[in] VariableName Name of variable.
1848 @param[in] VendorGuid Guid of variable.
1849 @param[in] Data Variable data.
1850 @param[in] DataSize Size of data. 0 means delete.
1851 @param[in] Attributes Attributes of the variable.
1852 @param[in] KeyIndex Index of associated public key.
1853 @param[in] MonotonicCount Value of associated monotonic count.
1854 @param[in, out] CacheVariable The variable information which is used to keep track of variable usage.
1855 @param[in] TimeStamp Value of associated TimeStamp.
1857 @retval EFI_SUCCESS The update operation is success.
1858 @retval EFI_OUT_OF_RESOURCES Variable region is full, can not write other data into this region.
1863 IN CHAR16
*VariableName
,
1864 IN EFI_GUID
*VendorGuid
,
1867 IN UINT32 Attributes OPTIONAL
,
1868 IN UINT32 KeyIndex OPTIONAL
,
1869 IN UINT64 MonotonicCount OPTIONAL
,
1870 IN OUT VARIABLE_POINTER_TRACK
*CacheVariable
,
1871 IN EFI_TIME
*TimeStamp OPTIONAL
1875 VARIABLE_HEADER
*NextVariable
;
1878 UINTN NonVolatileVarableStoreSize
;
1879 UINTN VarNameOffset
;
1880 UINTN VarDataOffset
;
1884 EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*Fvb
;
1886 VARIABLE_POINTER_TRACK
*Variable
;
1887 VARIABLE_POINTER_TRACK NvVariable
;
1888 VARIABLE_STORE_HEADER
*VariableStoreHeader
;
1890 UINT8
*BufferForMerge
;
1891 UINTN MergedBufSize
;
1895 if (mVariableModuleGlobal
->FvbInstance
== NULL
) {
1897 // The FVB protocol is not installed, so the EFI_VARIABLE_WRITE_ARCH_PROTOCOL is not installed.
1899 if ((Attributes
& EFI_VARIABLE_NON_VOLATILE
) != 0) {
1901 // Trying to update NV variable prior to the installation of EFI_VARIABLE_WRITE_ARCH_PROTOCOL
1903 return EFI_NOT_AVAILABLE_YET
;
1904 } else if ((Attributes
& EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS
) != 0) {
1906 // Trying to update volatile authenticated variable prior to the installation of EFI_VARIABLE_WRITE_ARCH_PROTOCOL
1907 // The authenticated variable perhaps is not initialized, just return here.
1909 return EFI_NOT_AVAILABLE_YET
;
1913 if ((CacheVariable
->CurrPtr
== NULL
) || CacheVariable
->Volatile
) {
1914 Variable
= CacheVariable
;
1917 // Update/Delete existing NV variable.
1918 // CacheVariable points to the variable in the memory copy of Flash area
1919 // Now let Variable points to the same variable in Flash area.
1921 VariableStoreHeader
= (VARIABLE_STORE_HEADER
*) ((UINTN
) mVariableModuleGlobal
->VariableGlobal
.NonVolatileVariableBase
);
1922 Variable
= &NvVariable
;
1923 Variable
->StartPtr
= GetStartPointer (VariableStoreHeader
);
1924 Variable
->EndPtr
= GetEndPointer (VariableStoreHeader
);
1925 Variable
->CurrPtr
= (VARIABLE_HEADER
*)((UINTN
)Variable
->StartPtr
+ ((UINTN
)CacheVariable
->CurrPtr
- (UINTN
)CacheVariable
->StartPtr
));
1926 if (CacheVariable
->InDeletedTransitionPtr
!= NULL
) {
1927 Variable
->InDeletedTransitionPtr
= (VARIABLE_HEADER
*)((UINTN
)Variable
->StartPtr
+ ((UINTN
)CacheVariable
->InDeletedTransitionPtr
- (UINTN
)CacheVariable
->StartPtr
));
1929 Variable
->InDeletedTransitionPtr
= NULL
;
1931 Variable
->Volatile
= FALSE
;
1934 Fvb
= mVariableModuleGlobal
->FvbInstance
;
1937 // Tricky part: Use scratch data area at the end of volatile variable store
1938 // as a temporary storage.
1940 NextVariable
= GetEndPointer ((VARIABLE_STORE_HEADER
*) ((UINTN
) mVariableModuleGlobal
->VariableGlobal
.VolatileVariableBase
));
1941 ScratchSize
= MAX (PcdGet32 (PcdMaxVariableSize
), PcdGet32 (PcdMaxHardwareErrorVariableSize
));
1942 SetMem (NextVariable
, ScratchSize
, 0xff);
1945 if (Variable
->CurrPtr
!= NULL
) {
1947 // Update/Delete existing variable.
1951 // If AtRuntime and the variable is Volatile and Runtime Access,
1952 // the volatile is ReadOnly, and SetVariable should be aborted and
1953 // return EFI_WRITE_PROTECTED.
1955 if (Variable
->Volatile
) {
1956 Status
= EFI_WRITE_PROTECTED
;
1960 // Only variable that have NV attributes can be updated/deleted in Runtime.
1962 if ((Variable
->CurrPtr
->Attributes
& EFI_VARIABLE_NON_VOLATILE
) == 0) {
1963 Status
= EFI_INVALID_PARAMETER
;
1968 // Only variable that have RT attributes can be updated/deleted in Runtime.
1970 if ((Variable
->CurrPtr
->Attributes
& EFI_VARIABLE_RUNTIME_ACCESS
) == 0) {
1971 Status
= EFI_INVALID_PARAMETER
;
1977 // Setting a data variable with no access, or zero DataSize attributes
1978 // causes it to be deleted.
1979 // When the EFI_VARIABLE_APPEND_WRITE attribute is set, DataSize of zero will
1980 // not delete the variable.
1982 if ((((Attributes
& EFI_VARIABLE_APPEND_WRITE
) == 0) && (DataSize
== 0))|| ((Attributes
& (EFI_VARIABLE_RUNTIME_ACCESS
| EFI_VARIABLE_BOOTSERVICE_ACCESS
)) == 0)) {
1983 if (Variable
->InDeletedTransitionPtr
!= NULL
) {
1985 // Both ADDED and IN_DELETED_TRANSITION variable are present,
1986 // set IN_DELETED_TRANSITION one to DELETED state first.
1988 State
= Variable
->InDeletedTransitionPtr
->State
;
1989 State
&= VAR_DELETED
;
1990 Status
= UpdateVariableStore (
1991 &mVariableModuleGlobal
->VariableGlobal
,
1995 (UINTN
) &Variable
->InDeletedTransitionPtr
->State
,
1999 if (!EFI_ERROR (Status
)) {
2000 if (!Variable
->Volatile
) {
2001 ASSERT (CacheVariable
->InDeletedTransitionPtr
!= NULL
);
2002 CacheVariable
->InDeletedTransitionPtr
->State
= State
;
2009 State
= Variable
->CurrPtr
->State
;
2010 State
&= VAR_DELETED
;
2012 Status
= UpdateVariableStore (
2013 &mVariableModuleGlobal
->VariableGlobal
,
2017 (UINTN
) &Variable
->CurrPtr
->State
,
2021 if (!EFI_ERROR (Status
)) {
2022 UpdateVariableInfo (VariableName
, VendorGuid
, Variable
->Volatile
, FALSE
, FALSE
, TRUE
, FALSE
);
2023 if (!Variable
->Volatile
) {
2024 CacheVariable
->CurrPtr
->State
= State
;
2025 FlushHobVariableToFlash (VariableName
, VendorGuid
);
2031 // If the variable is marked valid, and the same data has been passed in,
2032 // then return to the caller immediately.
2034 if (DataSizeOfVariable (Variable
->CurrPtr
) == DataSize
&&
2035 (CompareMem (Data
, GetVariableDataPtr (Variable
->CurrPtr
), DataSize
) == 0) &&
2036 ((Attributes
& EFI_VARIABLE_APPEND_WRITE
) == 0) &&
2037 (TimeStamp
== NULL
)) {
2039 // Variable content unchanged and no need to update timestamp, just return.
2041 UpdateVariableInfo (VariableName
, VendorGuid
, Variable
->Volatile
, FALSE
, TRUE
, FALSE
, FALSE
);
2042 Status
= EFI_SUCCESS
;
2044 } else if ((Variable
->CurrPtr
->State
== VAR_ADDED
) ||
2045 (Variable
->CurrPtr
->State
== (VAR_ADDED
& VAR_IN_DELETED_TRANSITION
))) {
2048 // EFI_VARIABLE_APPEND_WRITE attribute only effects for existing variable
2050 if ((Attributes
& EFI_VARIABLE_APPEND_WRITE
) != 0) {
2052 // NOTE: From 0 to DataOffset of NextVariable is reserved for Variable Header and Name.
2053 // From DataOffset of NextVariable is to save the existing variable data.
2055 DataOffset
= sizeof (VARIABLE_HEADER
) + Variable
->CurrPtr
->NameSize
+ GET_PAD_SIZE (Variable
->CurrPtr
->NameSize
);
2056 BufferForMerge
= (UINT8
*) ((UINTN
) NextVariable
+ DataOffset
);
2057 CopyMem (BufferForMerge
, (UINT8
*) ((UINTN
) Variable
->CurrPtr
+ DataOffset
), Variable
->CurrPtr
->DataSize
);
2060 // Set Max Common Variable Data Size as default MaxDataSize
2062 MaxDataSize
= PcdGet32 (PcdMaxVariableSize
) - DataOffset
;
2064 if ((CompareGuid (VendorGuid
, &gEfiImageSecurityDatabaseGuid
) &&
2065 ((StrCmp (VariableName
, EFI_IMAGE_SECURITY_DATABASE
) == 0) || (StrCmp (VariableName
, EFI_IMAGE_SECURITY_DATABASE1
) == 0) ||
2066 (StrCmp (VariableName
, EFI_IMAGE_SECURITY_DATABASE2
) == 0))) ||
2067 (CompareGuid (VendorGuid
, &gEfiGlobalVariableGuid
) && (StrCmp (VariableName
, EFI_KEY_EXCHANGE_KEY_NAME
) == 0))) {
2069 // For variables with formatted as EFI_SIGNATURE_LIST, the driver shall not perform an append of
2070 // EFI_SIGNATURE_DATA values that are already part of the existing variable value.
2072 Status
= AppendSignatureList (
2074 Variable
->CurrPtr
->DataSize
,
2075 MaxDataSize
- Variable
->CurrPtr
->DataSize
,
2080 if (Status
== EFI_BUFFER_TOO_SMALL
) {
2082 // Signature List is too long, Failed to Append.
2084 Status
= EFI_INVALID_PARAMETER
;
2088 if (MergedBufSize
== Variable
->CurrPtr
->DataSize
) {
2089 if ((TimeStamp
== NULL
) || CompareTimeStamp (TimeStamp
, &Variable
->CurrPtr
->TimeStamp
)) {
2091 // New EFI_SIGNATURE_DATA is not found and timestamp is not later
2092 // than current timestamp, return EFI_SUCCESS directly.
2094 UpdateVariableInfo (VariableName
, VendorGuid
, Variable
->Volatile
, FALSE
, TRUE
, FALSE
, FALSE
);
2095 Status
= EFI_SUCCESS
;
2101 // For other Variables, append the new data to the end of existing data.
2102 // Max Harware error record variable data size is different from common variable
2104 if ((Attributes
& EFI_VARIABLE_HARDWARE_ERROR_RECORD
) == EFI_VARIABLE_HARDWARE_ERROR_RECORD
) {
2105 MaxDataSize
= PcdGet32 (PcdMaxHardwareErrorVariableSize
) - DataOffset
;
2108 if (Variable
->CurrPtr
->DataSize
+ DataSize
> MaxDataSize
) {
2110 // Existing data size + new data size exceed maximum variable size limitation.
2112 Status
= EFI_INVALID_PARAMETER
;
2115 CopyMem ((UINT8
*) ((UINTN
) BufferForMerge
+ Variable
->CurrPtr
->DataSize
), Data
, DataSize
);
2116 MergedBufSize
= Variable
->CurrPtr
->DataSize
+ DataSize
;
2120 // BufferForMerge(from DataOffset of NextVariable) has included the merged existing and new data.
2122 Data
= BufferForMerge
;
2123 DataSize
= MergedBufSize
;
2128 // Mark the old variable as in delete transition.
2130 State
= Variable
->CurrPtr
->State
;
2131 State
&= VAR_IN_DELETED_TRANSITION
;
2133 Status
= UpdateVariableStore (
2134 &mVariableModuleGlobal
->VariableGlobal
,
2138 (UINTN
) &Variable
->CurrPtr
->State
,
2142 if (EFI_ERROR (Status
)) {
2145 if (!Variable
->Volatile
) {
2146 CacheVariable
->CurrPtr
->State
= State
;
2151 // Not found existing variable. Create a new variable.
2154 if ((DataSize
== 0) && ((Attributes
& EFI_VARIABLE_APPEND_WRITE
) != 0)) {
2155 Status
= EFI_SUCCESS
;
2160 // Make sure we are trying to create a new variable.
2161 // Setting a data variable with zero DataSize or no access attributes means to delete it.
2163 if (DataSize
== 0 || (Attributes
& (EFI_VARIABLE_RUNTIME_ACCESS
| EFI_VARIABLE_BOOTSERVICE_ACCESS
)) == 0) {
2164 Status
= EFI_NOT_FOUND
;
2169 // Only variable have NV|RT attribute can be created in Runtime.
2172 (((Attributes
& EFI_VARIABLE_RUNTIME_ACCESS
) == 0) || ((Attributes
& EFI_VARIABLE_NON_VOLATILE
) == 0))) {
2173 Status
= EFI_INVALID_PARAMETER
;
2179 // Function part - create a new variable and copy the data.
2180 // Both update a variable and create a variable will come here.
2182 NextVariable
->StartId
= VARIABLE_DATA
;
2184 // NextVariable->State = VAR_ADDED;
2186 NextVariable
->Reserved
= 0;
2187 NextVariable
->PubKeyIndex
= KeyIndex
;
2188 NextVariable
->MonotonicCount
= MonotonicCount
;
2189 ZeroMem (&NextVariable
->TimeStamp
, sizeof (EFI_TIME
));
2191 if (((Attributes
& EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS
) != 0) &&
2192 (TimeStamp
!= NULL
)) {
2193 if ((Attributes
& EFI_VARIABLE_APPEND_WRITE
) == 0) {
2194 CopyMem (&NextVariable
->TimeStamp
, TimeStamp
, sizeof (EFI_TIME
));
2197 // In the case when the EFI_VARIABLE_APPEND_WRITE attribute is set, only
2198 // when the new TimeStamp value is later than the current timestamp associated
2199 // with the variable, we need associate the new timestamp with the updated value.
2201 if (Variable
->CurrPtr
!= NULL
) {
2202 if (CompareTimeStamp (&Variable
->CurrPtr
->TimeStamp
, TimeStamp
)) {
2203 CopyMem (&NextVariable
->TimeStamp
, TimeStamp
, sizeof (EFI_TIME
));
2210 // The EFI_VARIABLE_APPEND_WRITE attribute will never be set in the returned
2211 // Attributes bitmask parameter of a GetVariable() call.
2213 NextVariable
->Attributes
= Attributes
& (~EFI_VARIABLE_APPEND_WRITE
);
2215 VarNameOffset
= sizeof (VARIABLE_HEADER
);
2216 VarNameSize
= StrSize (VariableName
);
2218 (UINT8
*) ((UINTN
) NextVariable
+ VarNameOffset
),
2222 VarDataOffset
= VarNameOffset
+ VarNameSize
+ GET_PAD_SIZE (VarNameSize
);
2225 // If DataReady is TRUE, it means the variable data has been saved into
2226 // NextVariable during EFI_VARIABLE_APPEND_WRITE operation preparation.
2230 (UINT8
*) ((UINTN
) NextVariable
+ VarDataOffset
),
2236 CopyMem (&NextVariable
->VendorGuid
, VendorGuid
, sizeof (EFI_GUID
));
2238 // There will be pad bytes after Data, the NextVariable->NameSize and
2239 // NextVariable->DataSize should not include pad size so that variable
2240 // service can get actual size in GetVariable.
2242 NextVariable
->NameSize
= (UINT32
)VarNameSize
;
2243 NextVariable
->DataSize
= (UINT32
)DataSize
;
2246 // The actual size of the variable that stores in storage should
2247 // include pad size.
2249 VarSize
= VarDataOffset
+ DataSize
+ GET_PAD_SIZE (DataSize
);
2250 if ((Attributes
& EFI_VARIABLE_NON_VOLATILE
) != 0) {
2252 // Create a nonvolatile variable.
2255 NonVolatileVarableStoreSize
= ((VARIABLE_STORE_HEADER
*)(UINTN
)(mVariableModuleGlobal
->VariableGlobal
.NonVolatileVariableBase
))->Size
;
2256 if ((((Attributes
& EFI_VARIABLE_HARDWARE_ERROR_RECORD
) != 0)
2257 && ((VarSize
+ mVariableModuleGlobal
->HwErrVariableTotalSize
) > PcdGet32 (PcdHwErrStorageSize
)))
2258 || (((Attributes
& EFI_VARIABLE_HARDWARE_ERROR_RECORD
) == 0)
2259 && ((VarSize
+ mVariableModuleGlobal
->CommonVariableTotalSize
) > NonVolatileVarableStoreSize
- sizeof (VARIABLE_STORE_HEADER
) - PcdGet32 (PcdHwErrStorageSize
)))) {
2261 Status
= EFI_OUT_OF_RESOURCES
;
2265 // Perform garbage collection & reclaim operation, and integrate the new variable at the same time.
2268 mVariableModuleGlobal
->VariableGlobal
.NonVolatileVariableBase
,
2269 &mVariableModuleGlobal
->NonVolatileLastVariableOffset
,
2273 HEADER_ALIGN (VarSize
),
2276 if (!EFI_ERROR (Status
)) {
2278 // The new variable has been integrated successfully during reclaiming.
2280 if (Variable
->CurrPtr
!= NULL
) {
2281 CacheVariable
->CurrPtr
= (VARIABLE_HEADER
*)((UINTN
) CacheVariable
->StartPtr
+ ((UINTN
) Variable
->CurrPtr
- (UINTN
) Variable
->StartPtr
));
2282 CacheVariable
->InDeletedTransitionPtr
= NULL
;
2284 UpdateVariableInfo (VariableName
, VendorGuid
, FALSE
, FALSE
, TRUE
, FALSE
, FALSE
);
2285 FlushHobVariableToFlash (VariableName
, VendorGuid
);
2291 // 1. Write variable header
2292 // 2. Set variable state to header valid
2293 // 3. Write variable data
2294 // 4. Set variable state to valid
2299 CacheOffset
= mVariableModuleGlobal
->NonVolatileLastVariableOffset
;
2300 Status
= UpdateVariableStore (
2301 &mVariableModuleGlobal
->VariableGlobal
,
2305 mVariableModuleGlobal
->NonVolatileLastVariableOffset
,
2306 sizeof (VARIABLE_HEADER
),
2307 (UINT8
*) NextVariable
2310 if (EFI_ERROR (Status
)) {
2317 NextVariable
->State
= VAR_HEADER_VALID_ONLY
;
2318 Status
= UpdateVariableStore (
2319 &mVariableModuleGlobal
->VariableGlobal
,
2323 mVariableModuleGlobal
->NonVolatileLastVariableOffset
+ OFFSET_OF (VARIABLE_HEADER
, State
),
2325 &NextVariable
->State
2328 if (EFI_ERROR (Status
)) {
2334 Status
= UpdateVariableStore (
2335 &mVariableModuleGlobal
->VariableGlobal
,
2339 mVariableModuleGlobal
->NonVolatileLastVariableOffset
+ sizeof (VARIABLE_HEADER
),
2340 (UINT32
) VarSize
- sizeof (VARIABLE_HEADER
),
2341 (UINT8
*) NextVariable
+ sizeof (VARIABLE_HEADER
)
2344 if (EFI_ERROR (Status
)) {
2350 NextVariable
->State
= VAR_ADDED
;
2351 Status
= UpdateVariableStore (
2352 &mVariableModuleGlobal
->VariableGlobal
,
2356 mVariableModuleGlobal
->NonVolatileLastVariableOffset
+ OFFSET_OF (VARIABLE_HEADER
, State
),
2358 &NextVariable
->State
2361 if (EFI_ERROR (Status
)) {
2365 mVariableModuleGlobal
->NonVolatileLastVariableOffset
+= HEADER_ALIGN (VarSize
);
2367 if ((Attributes
& EFI_VARIABLE_HARDWARE_ERROR_RECORD
) != 0) {
2368 mVariableModuleGlobal
->HwErrVariableTotalSize
+= HEADER_ALIGN (VarSize
);
2370 mVariableModuleGlobal
->CommonVariableTotalSize
+= HEADER_ALIGN (VarSize
);
2373 // update the memory copy of Flash region.
2375 CopyMem ((UINT8
*)mNvVariableCache
+ CacheOffset
, (UINT8
*)NextVariable
, VarSize
);
2378 // Create a volatile variable.
2382 if ((UINT32
) (VarSize
+ mVariableModuleGlobal
->VolatileLastVariableOffset
) >
2383 ((VARIABLE_STORE_HEADER
*) ((UINTN
) (mVariableModuleGlobal
->VariableGlobal
.VolatileVariableBase
)))->Size
) {
2385 // Perform garbage collection & reclaim operation, and integrate the new variable at the same time.
2388 mVariableModuleGlobal
->VariableGlobal
.VolatileVariableBase
,
2389 &mVariableModuleGlobal
->VolatileLastVariableOffset
,
2393 HEADER_ALIGN (VarSize
),
2396 if (!EFI_ERROR (Status
)) {
2398 // The new variable has been integrated successfully during reclaiming.
2400 if (Variable
->CurrPtr
!= NULL
) {
2401 CacheVariable
->CurrPtr
= (VARIABLE_HEADER
*)((UINTN
) CacheVariable
->StartPtr
+ ((UINTN
) Variable
->CurrPtr
- (UINTN
) Variable
->StartPtr
));
2402 CacheVariable
->InDeletedTransitionPtr
= NULL
;
2404 UpdateVariableInfo (VariableName
, VendorGuid
, TRUE
, FALSE
, TRUE
, FALSE
, FALSE
);
2409 NextVariable
->State
= VAR_ADDED
;
2410 Status
= UpdateVariableStore (
2411 &mVariableModuleGlobal
->VariableGlobal
,
2415 mVariableModuleGlobal
->VolatileLastVariableOffset
,
2417 (UINT8
*) NextVariable
2420 if (EFI_ERROR (Status
)) {
2424 mVariableModuleGlobal
->VolatileLastVariableOffset
+= HEADER_ALIGN (VarSize
);
2428 // Mark the old variable as deleted.
2430 if (!EFI_ERROR (Status
) && Variable
->CurrPtr
!= NULL
) {
2431 if (Variable
->InDeletedTransitionPtr
!= NULL
) {
2433 // Both ADDED and IN_DELETED_TRANSITION old variable are present,
2434 // set IN_DELETED_TRANSITION one to DELETED state first.
2436 State
= Variable
->InDeletedTransitionPtr
->State
;
2437 State
&= VAR_DELETED
;
2438 Status
= UpdateVariableStore (
2439 &mVariableModuleGlobal
->VariableGlobal
,
2443 (UINTN
) &Variable
->InDeletedTransitionPtr
->State
,
2447 if (!EFI_ERROR (Status
)) {
2448 if (!Variable
->Volatile
) {
2449 ASSERT (CacheVariable
->InDeletedTransitionPtr
!= NULL
);
2450 CacheVariable
->InDeletedTransitionPtr
->State
= State
;
2457 State
= Variable
->CurrPtr
->State
;
2458 State
&= VAR_DELETED
;
2460 Status
= UpdateVariableStore (
2461 &mVariableModuleGlobal
->VariableGlobal
,
2465 (UINTN
) &Variable
->CurrPtr
->State
,
2469 if (!EFI_ERROR (Status
) && !Variable
->Volatile
) {
2470 CacheVariable
->CurrPtr
->State
= State
;
2474 if (!EFI_ERROR (Status
)) {
2475 UpdateVariableInfo (VariableName
, VendorGuid
, Volatile
, FALSE
, TRUE
, FALSE
, FALSE
);
2477 FlushHobVariableToFlash (VariableName
, VendorGuid
);
2486 Check if a Unicode character is a hexadecimal character.
2488 This function checks if a Unicode character is a
2489 hexadecimal character. The valid hexadecimal character is
2490 L'0' to L'9', L'a' to L'f', or L'A' to L'F'.
2493 @param Char The character to check against.
2495 @retval TRUE If the Char is a hexadecmial character.
2496 @retval FALSE If the Char is not a hexadecmial character.
2501 IsHexaDecimalDigitCharacter (
2505 return (BOOLEAN
) ((Char
>= L
'0' && Char
<= L
'9') || (Char
>= L
'A' && Char
<= L
'F') || (Char
>= L
'a' && Char
<= L
'f'));
2510 This code checks if variable is hardware error record variable or not.
2512 According to UEFI spec, hardware error record variable should use the EFI_HARDWARE_ERROR_VARIABLE VendorGuid
2513 and have the L"HwErrRec####" name convention, #### is a printed hex value and no 0x or h is included in the hex value.
2515 @param VariableName Pointer to variable name.
2516 @param VendorGuid Variable Vendor Guid.
2518 @retval TRUE Variable is hardware error record variable.
2519 @retval FALSE Variable is not hardware error record variable.
2524 IsHwErrRecVariable (
2525 IN CHAR16
*VariableName
,
2526 IN EFI_GUID
*VendorGuid
2529 if (!CompareGuid (VendorGuid
, &gEfiHardwareErrorVariableGuid
) ||
2530 (StrLen (VariableName
) != StrLen (L
"HwErrRec####")) ||
2531 (StrnCmp(VariableName
, L
"HwErrRec", StrLen (L
"HwErrRec")) != 0) ||
2532 !IsHexaDecimalDigitCharacter (VariableName
[0x8]) ||
2533 !IsHexaDecimalDigitCharacter (VariableName
[0x9]) ||
2534 !IsHexaDecimalDigitCharacter (VariableName
[0xA]) ||
2535 !IsHexaDecimalDigitCharacter (VariableName
[0xB])) {
2543 Mark a variable that will become read-only after leaving the DXE phase of execution.
2545 @param[in] This The VARIABLE_LOCK_PROTOCOL instance.
2546 @param[in] VariableName A pointer to the variable name that will be made read-only subsequently.
2547 @param[in] VendorGuid A pointer to the vendor GUID that will be made read-only subsequently.
2549 @retval EFI_SUCCESS The variable specified by the VariableName and the VendorGuid was marked
2550 as pending to be read-only.
2551 @retval EFI_INVALID_PARAMETER VariableName or VendorGuid is NULL.
2552 Or VariableName is an empty string.
2553 @retval EFI_ACCESS_DENIED EFI_END_OF_DXE_EVENT_GROUP_GUID or EFI_EVENT_GROUP_READY_TO_BOOT has
2554 already been signaled.
2555 @retval EFI_OUT_OF_RESOURCES There is not enough resource to hold the lock request.
2559 VariableLockRequestToLock (
2560 IN CONST EDKII_VARIABLE_LOCK_PROTOCOL
*This
,
2561 IN CHAR16
*VariableName
,
2562 IN EFI_GUID
*VendorGuid
2565 VARIABLE_ENTRY
*Entry
;
2568 if (VariableName
== NULL
|| VariableName
[0] == 0 || VendorGuid
== NULL
) {
2569 return EFI_INVALID_PARAMETER
;
2573 return EFI_ACCESS_DENIED
;
2576 Entry
= AllocateRuntimeZeroPool (sizeof (*Entry
) + StrSize (VariableName
));
2577 if (Entry
== NULL
) {
2578 return EFI_OUT_OF_RESOURCES
;
2581 DEBUG ((EFI_D_INFO
, "[Variable] Lock: %g:%s\n", VendorGuid
, VariableName
));
2583 AcquireLockOnlyAtBootTime(&mVariableModuleGlobal
->VariableGlobal
.VariableServicesLock
);
2585 Name
= (CHAR16
*) ((UINTN
) Entry
+ sizeof (*Entry
));
2586 StrnCpy (Name
, VariableName
, StrLen (VariableName
));
2587 CopyGuid (&Entry
->Guid
, VendorGuid
);
2588 InsertTailList (&mLockedVariableList
, &Entry
->Link
);
2590 ReleaseLockOnlyAtBootTime (&mVariableModuleGlobal
->VariableGlobal
.VariableServicesLock
);
2597 This code finds variable in storage blocks (Volatile or Non-Volatile).
2599 Caution: This function may receive untrusted input.
2600 This function may be invoked in SMM mode, and datasize is external input.
2601 This function will do basic validation, before parse the data.
2603 @param VariableName Name of Variable to be found.
2604 @param VendorGuid Variable vendor GUID.
2605 @param Attributes Attribute value of the variable found.
2606 @param DataSize Size of Data found. If size is less than the
2607 data, this value contains the required size.
2608 @param Data Data pointer.
2610 @return EFI_INVALID_PARAMETER Invalid parameter.
2611 @return EFI_SUCCESS Find the specified variable.
2612 @return EFI_NOT_FOUND Not found.
2613 @return EFI_BUFFER_TO_SMALL DataSize is too small for the result.
2618 VariableServiceGetVariable (
2619 IN CHAR16
*VariableName
,
2620 IN EFI_GUID
*VendorGuid
,
2621 OUT UINT32
*Attributes OPTIONAL
,
2622 IN OUT UINTN
*DataSize
,
2627 VARIABLE_POINTER_TRACK Variable
;
2630 if (VariableName
== NULL
|| VendorGuid
== NULL
|| DataSize
== NULL
) {
2631 return EFI_INVALID_PARAMETER
;
2634 AcquireLockOnlyAtBootTime(&mVariableModuleGlobal
->VariableGlobal
.VariableServicesLock
);
2636 Status
= FindVariable (VariableName
, VendorGuid
, &Variable
, &mVariableModuleGlobal
->VariableGlobal
, FALSE
);
2637 if (Variable
.CurrPtr
== NULL
|| EFI_ERROR (Status
)) {
2644 VarDataSize
= DataSizeOfVariable (Variable
.CurrPtr
);
2645 ASSERT (VarDataSize
!= 0);
2647 if (*DataSize
>= VarDataSize
) {
2649 Status
= EFI_INVALID_PARAMETER
;
2653 CopyMem (Data
, GetVariableDataPtr (Variable
.CurrPtr
), VarDataSize
);
2654 if (Attributes
!= NULL
) {
2655 *Attributes
= Variable
.CurrPtr
->Attributes
;
2658 *DataSize
= VarDataSize
;
2659 UpdateVariableInfo (VariableName
, VendorGuid
, Variable
.Volatile
, TRUE
, FALSE
, FALSE
, FALSE
);
2661 Status
= EFI_SUCCESS
;
2664 *DataSize
= VarDataSize
;
2665 Status
= EFI_BUFFER_TOO_SMALL
;
2670 ReleaseLockOnlyAtBootTime (&mVariableModuleGlobal
->VariableGlobal
.VariableServicesLock
);
2678 This code Finds the Next available variable.
2680 Caution: This function may receive untrusted input.
2681 This function may be invoked in SMM mode. This function will do basic validation, before parse the data.
2683 @param VariableNameSize Size of the variable name.
2684 @param VariableName Pointer to variable name.
2685 @param VendorGuid Variable Vendor Guid.
2687 @return EFI_INVALID_PARAMETER Invalid parameter.
2688 @return EFI_SUCCESS Find the specified variable.
2689 @return EFI_NOT_FOUND Not found.
2690 @return EFI_BUFFER_TO_SMALL DataSize is too small for the result.
2695 VariableServiceGetNextVariableName (
2696 IN OUT UINTN
*VariableNameSize
,
2697 IN OUT CHAR16
*VariableName
,
2698 IN OUT EFI_GUID
*VendorGuid
2701 VARIABLE_STORE_TYPE Type
;
2702 VARIABLE_POINTER_TRACK Variable
;
2703 VARIABLE_POINTER_TRACK VariableInHob
;
2704 VARIABLE_POINTER_TRACK VariablePtrTrack
;
2707 VARIABLE_STORE_HEADER
*VariableStoreHeader
[VariableStoreTypeMax
];
2709 if (VariableNameSize
== NULL
|| VariableName
== NULL
|| VendorGuid
== NULL
) {
2710 return EFI_INVALID_PARAMETER
;
2713 AcquireLockOnlyAtBootTime(&mVariableModuleGlobal
->VariableGlobal
.VariableServicesLock
);
2715 Status
= FindVariable (VariableName
, VendorGuid
, &Variable
, &mVariableModuleGlobal
->VariableGlobal
, FALSE
);
2716 if (Variable
.CurrPtr
== NULL
|| EFI_ERROR (Status
)) {
2720 if (VariableName
[0] != 0) {
2722 // If variable name is not NULL, get next variable.
2724 Variable
.CurrPtr
= GetNextVariablePtr (Variable
.CurrPtr
);
2728 // 0: Volatile, 1: HOB, 2: Non-Volatile.
2729 // The index and attributes mapping must be kept in this order as FindVariable
2730 // makes use of this mapping to implement search algorithm.
2732 VariableStoreHeader
[VariableStoreTypeVolatile
] = (VARIABLE_STORE_HEADER
*) (UINTN
) mVariableModuleGlobal
->VariableGlobal
.VolatileVariableBase
;
2733 VariableStoreHeader
[VariableStoreTypeHob
] = (VARIABLE_STORE_HEADER
*) (UINTN
) mVariableModuleGlobal
->VariableGlobal
.HobVariableBase
;
2734 VariableStoreHeader
[VariableStoreTypeNv
] = mNvVariableCache
;
2738 // Switch from Volatile to HOB, to Non-Volatile.
2740 while (!IsValidVariableHeader (Variable
.CurrPtr
, Variable
.EndPtr
)) {
2742 // Find current storage index
2744 for (Type
= (VARIABLE_STORE_TYPE
) 0; Type
< VariableStoreTypeMax
; Type
++) {
2745 if ((VariableStoreHeader
[Type
] != NULL
) && (Variable
.StartPtr
== GetStartPointer (VariableStoreHeader
[Type
]))) {
2749 ASSERT (Type
< VariableStoreTypeMax
);
2751 // Switch to next storage
2753 for (Type
++; Type
< VariableStoreTypeMax
; Type
++) {
2754 if (VariableStoreHeader
[Type
] != NULL
) {
2759 // Capture the case that
2760 // 1. current storage is the last one, or
2761 // 2. no further storage
2763 if (Type
== VariableStoreTypeMax
) {
2764 Status
= EFI_NOT_FOUND
;
2767 Variable
.StartPtr
= GetStartPointer (VariableStoreHeader
[Type
]);
2768 Variable
.EndPtr
= GetEndPointer (VariableStoreHeader
[Type
]);
2769 Variable
.CurrPtr
= Variable
.StartPtr
;
2773 // Variable is found
2775 if (Variable
.CurrPtr
->State
== VAR_ADDED
|| Variable
.CurrPtr
->State
== (VAR_IN_DELETED_TRANSITION
& VAR_ADDED
)) {
2776 if (!AtRuntime () || ((Variable
.CurrPtr
->Attributes
& EFI_VARIABLE_RUNTIME_ACCESS
) != 0)) {
2777 if (Variable
.CurrPtr
->State
== (VAR_IN_DELETED_TRANSITION
& VAR_ADDED
)) {
2779 // If it is a IN_DELETED_TRANSITION variable,
2780 // and there is also a same ADDED one at the same time,
2783 VariablePtrTrack
.StartPtr
= Variable
.StartPtr
;
2784 VariablePtrTrack
.EndPtr
= Variable
.EndPtr
;
2785 Status
= FindVariableEx (
2786 GetVariableNamePtr (Variable
.CurrPtr
),
2787 &Variable
.CurrPtr
->VendorGuid
,
2791 if (!EFI_ERROR (Status
) && VariablePtrTrack
.CurrPtr
->State
== VAR_ADDED
) {
2792 Variable
.CurrPtr
= GetNextVariablePtr (Variable
.CurrPtr
);
2798 // Don't return NV variable when HOB overrides it
2800 if ((VariableStoreHeader
[VariableStoreTypeHob
] != NULL
) && (VariableStoreHeader
[VariableStoreTypeNv
] != NULL
) &&
2801 (Variable
.StartPtr
== GetStartPointer (VariableStoreHeader
[VariableStoreTypeNv
]))
2803 VariableInHob
.StartPtr
= GetStartPointer (VariableStoreHeader
[VariableStoreTypeHob
]);
2804 VariableInHob
.EndPtr
= GetEndPointer (VariableStoreHeader
[VariableStoreTypeHob
]);
2805 Status
= FindVariableEx (
2806 GetVariableNamePtr (Variable
.CurrPtr
),
2807 &Variable
.CurrPtr
->VendorGuid
,
2811 if (!EFI_ERROR (Status
)) {
2812 Variable
.CurrPtr
= GetNextVariablePtr (Variable
.CurrPtr
);
2817 VarNameSize
= NameSizeOfVariable (Variable
.CurrPtr
);
2818 ASSERT (VarNameSize
!= 0);
2820 if (VarNameSize
<= *VariableNameSize
) {
2821 CopyMem (VariableName
, GetVariableNamePtr (Variable
.CurrPtr
), VarNameSize
);
2822 CopyMem (VendorGuid
, &Variable
.CurrPtr
->VendorGuid
, sizeof (EFI_GUID
));
2823 Status
= EFI_SUCCESS
;
2825 Status
= EFI_BUFFER_TOO_SMALL
;
2828 *VariableNameSize
= VarNameSize
;
2833 Variable
.CurrPtr
= GetNextVariablePtr (Variable
.CurrPtr
);
2837 ReleaseLockOnlyAtBootTime (&mVariableModuleGlobal
->VariableGlobal
.VariableServicesLock
);
2843 This code sets variable in storage blocks (Volatile or Non-Volatile).
2845 Caution: This function may receive untrusted input.
2846 This function may be invoked in SMM mode, and datasize and data are external input.
2847 This function will do basic validation, before parse the data.
2848 This function will parse the authentication carefully to avoid security issues, like
2849 buffer overflow, integer overflow.
2850 This function will check attribute carefully to avoid authentication bypass.
2852 @param VariableName Name of Variable to be found.
2853 @param VendorGuid Variable vendor GUID.
2854 @param Attributes Attribute value of the variable found
2855 @param DataSize Size of Data found. If size is less than the
2856 data, this value contains the required size.
2857 @param Data Data pointer.
2859 @return EFI_INVALID_PARAMETER Invalid parameter.
2860 @return EFI_SUCCESS Set successfully.
2861 @return EFI_OUT_OF_RESOURCES Resource not enough to set variable.
2862 @return EFI_NOT_FOUND Not found.
2863 @return EFI_WRITE_PROTECTED Variable is read-only.
2868 VariableServiceSetVariable (
2869 IN CHAR16
*VariableName
,
2870 IN EFI_GUID
*VendorGuid
,
2871 IN UINT32 Attributes
,
2876 VARIABLE_POINTER_TRACK Variable
;
2878 VARIABLE_HEADER
*NextVariable
;
2879 EFI_PHYSICAL_ADDRESS Point
;
2882 VARIABLE_ENTRY
*Entry
;
2886 // Check input parameters.
2888 if (VariableName
== NULL
|| VariableName
[0] == 0 || VendorGuid
== NULL
) {
2889 return EFI_INVALID_PARAMETER
;
2892 if (DataSize
!= 0 && Data
== NULL
) {
2893 return EFI_INVALID_PARAMETER
;
2897 // Check for reserverd bit in variable attribute.
2899 if ((Attributes
& (~EFI_VARIABLE_ATTRIBUTES_MASK
)) != 0) {
2900 return EFI_INVALID_PARAMETER
;
2904 // Make sure if runtime bit is set, boot service bit is set also.
2906 if ((Attributes
& (EFI_VARIABLE_RUNTIME_ACCESS
| EFI_VARIABLE_BOOTSERVICE_ACCESS
)) == EFI_VARIABLE_RUNTIME_ACCESS
) {
2907 return EFI_INVALID_PARAMETER
;
2911 // EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS and EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS attribute
2912 // cannot be set both.
2914 if (((Attributes
& EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS
) == EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS
)
2915 && ((Attributes
& EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS
) == EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS
)) {
2916 return EFI_INVALID_PARAMETER
;
2919 if ((Attributes
& EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS
) == EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS
) {
2920 if (DataSize
< AUTHINFO_SIZE
) {
2922 // Try to write Authenticated Variable without AuthInfo.
2924 return EFI_SECURITY_VIOLATION
;
2926 PayloadSize
= DataSize
- AUTHINFO_SIZE
;
2927 } else if ((Attributes
& EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS
) == EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS
) {
2929 // Sanity check for EFI_VARIABLE_AUTHENTICATION_2 descriptor.
2931 if (DataSize
< OFFSET_OF_AUTHINFO2_CERT_DATA
||
2932 ((EFI_VARIABLE_AUTHENTICATION_2
*) Data
)->AuthInfo
.Hdr
.dwLength
> DataSize
- (OFFSET_OF (EFI_VARIABLE_AUTHENTICATION_2
, AuthInfo
)) ||
2933 ((EFI_VARIABLE_AUTHENTICATION_2
*) Data
)->AuthInfo
.Hdr
.dwLength
< OFFSET_OF (WIN_CERTIFICATE_UEFI_GUID
, CertData
)) {
2934 return EFI_SECURITY_VIOLATION
;
2936 PayloadSize
= DataSize
- AUTHINFO2_SIZE (Data
);
2938 PayloadSize
= DataSize
;
2941 if ((UINTN
)(~0) - PayloadSize
< StrSize(VariableName
)){
2943 // Prevent whole variable size overflow
2945 return EFI_INVALID_PARAMETER
;
2949 // The size of the VariableName, including the Unicode Null in bytes plus
2950 // the DataSize is limited to maximum size of PcdGet32 (PcdMaxHardwareErrorVariableSize)
2951 // bytes for HwErrRec, and PcdGet32 (PcdMaxVariableSize) bytes for the others.
2953 if ((Attributes
& EFI_VARIABLE_HARDWARE_ERROR_RECORD
) == EFI_VARIABLE_HARDWARE_ERROR_RECORD
) {
2954 if (StrSize (VariableName
) + PayloadSize
> PcdGet32 (PcdMaxHardwareErrorVariableSize
) - sizeof (VARIABLE_HEADER
)) {
2955 return EFI_INVALID_PARAMETER
;
2957 if (!IsHwErrRecVariable(VariableName
, VendorGuid
)) {
2958 return EFI_INVALID_PARAMETER
;
2962 // The size of the VariableName, including the Unicode Null in bytes plus
2963 // the DataSize is limited to maximum size of PcdGet32 (PcdMaxVariableSize) bytes.
2965 if (StrSize (VariableName
) + PayloadSize
> PcdGet32 (PcdMaxVariableSize
) - sizeof (VARIABLE_HEADER
)) {
2966 return EFI_INVALID_PARAMETER
;
2970 AcquireLockOnlyAtBootTime(&mVariableModuleGlobal
->VariableGlobal
.VariableServicesLock
);
2973 // Consider reentrant in MCA/INIT/NMI. It needs be reupdated.
2975 if (1 < InterlockedIncrement (&mVariableModuleGlobal
->VariableGlobal
.ReentrantState
)) {
2976 Point
= mVariableModuleGlobal
->VariableGlobal
.NonVolatileVariableBase
;
2978 // Parse non-volatile variable data and get last variable offset.
2980 NextVariable
= GetStartPointer ((VARIABLE_STORE_HEADER
*) (UINTN
) Point
);
2981 while (IsValidVariableHeader (NextVariable
, GetEndPointer ((VARIABLE_STORE_HEADER
*) (UINTN
) Point
))) {
2982 NextVariable
= GetNextVariablePtr (NextVariable
);
2984 mVariableModuleGlobal
->NonVolatileLastVariableOffset
= (UINTN
) NextVariable
- (UINTN
) Point
;
2987 if (mEndOfDxe
&& mEnableLocking
) {
2989 // Treat the variables listed in the forbidden variable list as read-only after leaving DXE phase.
2991 for ( Link
= GetFirstNode (&mLockedVariableList
)
2992 ; !IsNull (&mLockedVariableList
, Link
)
2993 ; Link
= GetNextNode (&mLockedVariableList
, Link
)
2995 Entry
= BASE_CR (Link
, VARIABLE_ENTRY
, Link
);
2996 Name
= (CHAR16
*) ((UINTN
) Entry
+ sizeof (*Entry
));
2997 if (CompareGuid (&Entry
->Guid
, VendorGuid
) && (StrCmp (Name
, VariableName
) == 0)) {
2998 Status
= EFI_WRITE_PROTECTED
;
2999 DEBUG ((EFI_D_INFO
, "[Variable]: Changing readonly variable after leaving DXE phase - %g:%s\n", VendorGuid
, VariableName
));
3005 Status
= InternalVarCheckSetVariableCheck (VariableName
, VendorGuid
, Attributes
, PayloadSize
, (VOID
*) ((UINTN
) Data
+ DataSize
- PayloadSize
));
3006 if (EFI_ERROR (Status
)) {
3011 // Check whether the input variable is already existed.
3013 Status
= FindVariable (VariableName
, VendorGuid
, &Variable
, &mVariableModuleGlobal
->VariableGlobal
, TRUE
);
3014 if (!EFI_ERROR (Status
)) {
3015 if (((Variable
.CurrPtr
->Attributes
& EFI_VARIABLE_RUNTIME_ACCESS
) == 0) && AtRuntime ()) {
3016 Status
= EFI_WRITE_PROTECTED
;
3019 if (Attributes
!= 0 && (Attributes
& (~EFI_VARIABLE_APPEND_WRITE
)) != Variable
.CurrPtr
->Attributes
) {
3021 // If a preexisting variable is rewritten with different attributes, SetVariable() shall not
3022 // modify the variable and shall return EFI_INVALID_PARAMETER. Two exceptions to this rule:
3023 // 1. No access attributes specified
3024 // 2. The only attribute differing is EFI_VARIABLE_APPEND_WRITE
3026 Status
= EFI_INVALID_PARAMETER
;
3027 DEBUG ((EFI_D_INFO
, "[Variable]: Rewritten a preexisting variable with different attributes - %g:%s\n", VendorGuid
, VariableName
));
3032 if (!FeaturePcdGet (PcdUefiVariableDefaultLangDeprecate
)) {
3034 // Hook the operation of setting PlatformLangCodes/PlatformLang and LangCodes/Lang.
3036 Status
= AutoUpdateLangVariable (VariableName
, Data
, DataSize
);
3037 if (EFI_ERROR (Status
)) {
3039 // The auto update operation failed, directly return to avoid inconsistency between PlatformLang and Lang.
3046 // Process PK, KEK, Sigdb seperately.
3048 if (CompareGuid (VendorGuid
, &gEfiGlobalVariableGuid
) && (StrCmp (VariableName
, EFI_PLATFORM_KEY_NAME
) == 0)){
3049 Status
= ProcessVarWithPk (VariableName
, VendorGuid
, Data
, DataSize
, &Variable
, Attributes
, TRUE
);
3050 } else if (CompareGuid (VendorGuid
, &gEfiGlobalVariableGuid
) && (StrCmp (VariableName
, EFI_KEY_EXCHANGE_KEY_NAME
) == 0)) {
3051 Status
= ProcessVarWithPk (VariableName
, VendorGuid
, Data
, DataSize
, &Variable
, Attributes
, FALSE
);
3052 } else if (CompareGuid (VendorGuid
, &gEfiImageSecurityDatabaseGuid
) &&
3053 ((StrCmp (VariableName
, EFI_IMAGE_SECURITY_DATABASE
) == 0) ||
3054 (StrCmp (VariableName
, EFI_IMAGE_SECURITY_DATABASE1
) == 0) ||
3055 (StrCmp (VariableName
, EFI_IMAGE_SECURITY_DATABASE2
) == 0)
3058 Status
= ProcessVarWithPk (VariableName
, VendorGuid
, Data
, DataSize
, &Variable
, Attributes
, FALSE
);
3059 if (EFI_ERROR (Status
)) {
3060 Status
= ProcessVarWithKek (VariableName
, VendorGuid
, Data
, DataSize
, &Variable
, Attributes
);
3063 Status
= ProcessVariable (VariableName
, VendorGuid
, Data
, DataSize
, &Variable
, Attributes
);
3067 InterlockedDecrement (&mVariableModuleGlobal
->VariableGlobal
.ReentrantState
);
3068 ReleaseLockOnlyAtBootTime (&mVariableModuleGlobal
->VariableGlobal
.VariableServicesLock
);
3070 if (!AtRuntime ()) {
3071 if (!EFI_ERROR (Status
)) {
3084 This code returns information about the EFI variables.
3086 Caution: This function may receive untrusted input.
3087 This function may be invoked in SMM mode. This function will do basic validation, before parse the data.
3089 @param Attributes Attributes bitmask to specify the type of variables
3090 on which to return information.
3091 @param MaximumVariableStorageSize Pointer to the maximum size of the storage space available
3092 for the EFI variables associated with the attributes specified.
3093 @param RemainingVariableStorageSize Pointer to the remaining size of the storage space available
3094 for EFI variables associated with the attributes specified.
3095 @param MaximumVariableSize Pointer to the maximum size of an individual EFI variables
3096 associated with the attributes specified.
3098 @return EFI_SUCCESS Query successfully.
3103 VariableServiceQueryVariableInfoInternal (
3104 IN UINT32 Attributes
,
3105 OUT UINT64
*MaximumVariableStorageSize
,
3106 OUT UINT64
*RemainingVariableStorageSize
,
3107 OUT UINT64
*MaximumVariableSize
3110 VARIABLE_HEADER
*Variable
;
3111 VARIABLE_HEADER
*NextVariable
;
3112 UINT64 VariableSize
;
3113 VARIABLE_STORE_HEADER
*VariableStoreHeader
;
3114 UINT64 CommonVariableTotalSize
;
3115 UINT64 HwErrVariableTotalSize
;
3117 VARIABLE_POINTER_TRACK VariablePtrTrack
;
3119 CommonVariableTotalSize
= 0;
3120 HwErrVariableTotalSize
= 0;
3122 if((Attributes
& EFI_VARIABLE_NON_VOLATILE
) == 0) {
3124 // Query is Volatile related.
3126 VariableStoreHeader
= (VARIABLE_STORE_HEADER
*) ((UINTN
) mVariableModuleGlobal
->VariableGlobal
.VolatileVariableBase
);
3129 // Query is Non-Volatile related.
3131 VariableStoreHeader
= mNvVariableCache
;
3135 // Now let's fill *MaximumVariableStorageSize *RemainingVariableStorageSize
3136 // with the storage size (excluding the storage header size).
3138 *MaximumVariableStorageSize
= VariableStoreHeader
->Size
- sizeof (VARIABLE_STORE_HEADER
);
3141 // Harware error record variable needs larger size.
3143 if ((Attributes
& (EFI_VARIABLE_NON_VOLATILE
| EFI_VARIABLE_HARDWARE_ERROR_RECORD
)) == (EFI_VARIABLE_NON_VOLATILE
| EFI_VARIABLE_HARDWARE_ERROR_RECORD
)) {
3144 *MaximumVariableStorageSize
= PcdGet32 (PcdHwErrStorageSize
);
3145 *MaximumVariableSize
= PcdGet32 (PcdMaxHardwareErrorVariableSize
) - sizeof (VARIABLE_HEADER
);
3147 if ((Attributes
& EFI_VARIABLE_NON_VOLATILE
) != 0) {
3148 ASSERT (PcdGet32 (PcdHwErrStorageSize
) < VariableStoreHeader
->Size
);
3149 *MaximumVariableStorageSize
= VariableStoreHeader
->Size
- sizeof (VARIABLE_STORE_HEADER
) - PcdGet32 (PcdHwErrStorageSize
);
3153 // Let *MaximumVariableSize be PcdGet32 (PcdMaxVariableSize) with the exception of the variable header size.
3155 *MaximumVariableSize
= PcdGet32 (PcdMaxVariableSize
) - sizeof (VARIABLE_HEADER
);
3159 // Point to the starting address of the variables.
3161 Variable
= GetStartPointer (VariableStoreHeader
);
3164 // Now walk through the related variable store.
3166 while (IsValidVariableHeader (Variable
, GetEndPointer (VariableStoreHeader
))) {
3167 NextVariable
= GetNextVariablePtr (Variable
);
3168 VariableSize
= (UINT64
) (UINTN
) NextVariable
- (UINT64
) (UINTN
) Variable
;
3172 // We don't take the state of the variables in mind
3173 // when calculating RemainingVariableStorageSize,
3174 // since the space occupied by variables not marked with
3175 // VAR_ADDED is not allowed to be reclaimed in Runtime.
3177 if ((Variable
->Attributes
& EFI_VARIABLE_HARDWARE_ERROR_RECORD
) == EFI_VARIABLE_HARDWARE_ERROR_RECORD
) {
3178 HwErrVariableTotalSize
+= VariableSize
;
3180 CommonVariableTotalSize
+= VariableSize
;
3184 // Only care about Variables with State VAR_ADDED, because
3185 // the space not marked as VAR_ADDED is reclaimable now.
3187 if (Variable
->State
== VAR_ADDED
) {
3188 if ((Variable
->Attributes
& EFI_VARIABLE_HARDWARE_ERROR_RECORD
) == EFI_VARIABLE_HARDWARE_ERROR_RECORD
) {
3189 HwErrVariableTotalSize
+= VariableSize
;
3191 CommonVariableTotalSize
+= VariableSize
;
3193 } else if (Variable
->State
== (VAR_IN_DELETED_TRANSITION
& VAR_ADDED
)) {
3195 // If it is a IN_DELETED_TRANSITION variable,
3196 // and there is not also a same ADDED one at the same time,
3197 // this IN_DELETED_TRANSITION variable is valid.
3199 VariablePtrTrack
.StartPtr
= GetStartPointer (VariableStoreHeader
);
3200 VariablePtrTrack
.EndPtr
= GetEndPointer (VariableStoreHeader
);
3201 Status
= FindVariableEx (
3202 GetVariableNamePtr (Variable
),
3203 &Variable
->VendorGuid
,
3207 if (!EFI_ERROR (Status
) && VariablePtrTrack
.CurrPtr
->State
!= VAR_ADDED
) {
3208 if ((Variable
->Attributes
& EFI_VARIABLE_HARDWARE_ERROR_RECORD
) == EFI_VARIABLE_HARDWARE_ERROR_RECORD
) {
3209 HwErrVariableTotalSize
+= VariableSize
;
3211 CommonVariableTotalSize
+= VariableSize
;
3218 // Go to the next one.
3220 Variable
= NextVariable
;
3223 if ((Attributes
& EFI_VARIABLE_HARDWARE_ERROR_RECORD
) == EFI_VARIABLE_HARDWARE_ERROR_RECORD
){
3224 *RemainingVariableStorageSize
= *MaximumVariableStorageSize
- HwErrVariableTotalSize
;
3226 *RemainingVariableStorageSize
= *MaximumVariableStorageSize
- CommonVariableTotalSize
;
3229 if (*RemainingVariableStorageSize
< sizeof (VARIABLE_HEADER
)) {
3230 *MaximumVariableSize
= 0;
3231 } else if ((*RemainingVariableStorageSize
- sizeof (VARIABLE_HEADER
)) < *MaximumVariableSize
) {
3232 *MaximumVariableSize
= *RemainingVariableStorageSize
- sizeof (VARIABLE_HEADER
);
3240 This code returns information about the EFI variables.
3242 Caution: This function may receive untrusted input.
3243 This function may be invoked in SMM mode. This function will do basic validation, before parse the data.
3245 @param Attributes Attributes bitmask to specify the type of variables
3246 on which to return information.
3247 @param MaximumVariableStorageSize Pointer to the maximum size of the storage space available
3248 for the EFI variables associated with the attributes specified.
3249 @param RemainingVariableStorageSize Pointer to the remaining size of the storage space available
3250 for EFI variables associated with the attributes specified.
3251 @param MaximumVariableSize Pointer to the maximum size of an individual EFI variables
3252 associated with the attributes specified.
3254 @return EFI_INVALID_PARAMETER An invalid combination of attribute bits was supplied.
3255 @return EFI_SUCCESS Query successfully.
3256 @return EFI_UNSUPPORTED The attribute is not supported on this platform.
3261 VariableServiceQueryVariableInfo (
3262 IN UINT32 Attributes
,
3263 OUT UINT64
*MaximumVariableStorageSize
,
3264 OUT UINT64
*RemainingVariableStorageSize
,
3265 OUT UINT64
*MaximumVariableSize
3270 if(MaximumVariableStorageSize
== NULL
|| RemainingVariableStorageSize
== NULL
|| MaximumVariableSize
== NULL
|| Attributes
== 0) {
3271 return EFI_INVALID_PARAMETER
;
3274 if((Attributes
& (EFI_VARIABLE_NON_VOLATILE
| EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_RUNTIME_ACCESS
| EFI_VARIABLE_HARDWARE_ERROR_RECORD
)) == 0) {
3276 // Make sure the Attributes combination is supported by the platform.
3278 return EFI_UNSUPPORTED
;
3279 } else if ((Attributes
& (EFI_VARIABLE_RUNTIME_ACCESS
| EFI_VARIABLE_BOOTSERVICE_ACCESS
)) == EFI_VARIABLE_RUNTIME_ACCESS
) {
3281 // Make sure if runtime bit is set, boot service bit is set also.
3283 return EFI_INVALID_PARAMETER
;
3284 } else if (AtRuntime () && ((Attributes
& EFI_VARIABLE_RUNTIME_ACCESS
) == 0)) {
3286 // Make sure RT Attribute is set if we are in Runtime phase.
3288 return EFI_INVALID_PARAMETER
;
3289 } else if ((Attributes
& (EFI_VARIABLE_NON_VOLATILE
| EFI_VARIABLE_HARDWARE_ERROR_RECORD
)) == EFI_VARIABLE_HARDWARE_ERROR_RECORD
) {
3291 // Make sure Hw Attribute is set with NV.
3293 return EFI_INVALID_PARAMETER
;
3296 AcquireLockOnlyAtBootTime(&mVariableModuleGlobal
->VariableGlobal
.VariableServicesLock
);
3298 Status
= VariableServiceQueryVariableInfoInternal (
3300 MaximumVariableStorageSize
,
3301 RemainingVariableStorageSize
,
3305 ReleaseLockOnlyAtBootTime (&mVariableModuleGlobal
->VariableGlobal
.VariableServicesLock
);
3310 This function reclaims variable storage if free size is below the threshold.
3312 Caution: This function may be invoked at SMM mode.
3313 Care must be taken to make sure not security issue.
3322 UINTN CommonVariableSpace
;
3323 UINTN RemainingCommonVariableSpace
;
3324 UINTN RemainingHwErrVariableSpace
;
3326 Status
= EFI_SUCCESS
;
3328 CommonVariableSpace
= ((VARIABLE_STORE_HEADER
*) ((UINTN
) (mVariableModuleGlobal
->VariableGlobal
.NonVolatileVariableBase
)))->Size
- sizeof (VARIABLE_STORE_HEADER
) - PcdGet32(PcdHwErrStorageSize
); //Allowable max size of common variable storage space
3330 RemainingCommonVariableSpace
= CommonVariableSpace
- mVariableModuleGlobal
->CommonVariableTotalSize
;
3332 RemainingHwErrVariableSpace
= PcdGet32 (PcdHwErrStorageSize
) - mVariableModuleGlobal
->HwErrVariableTotalSize
;
3334 // Check if the free area is blow a threshold.
3336 if ((RemainingCommonVariableSpace
< PcdGet32 (PcdMaxVariableSize
))
3337 || ((PcdGet32 (PcdHwErrStorageSize
) != 0) &&
3338 (RemainingHwErrVariableSpace
< PcdGet32 (PcdMaxHardwareErrorVariableSize
)))){
3340 mVariableModuleGlobal
->VariableGlobal
.NonVolatileVariableBase
,
3341 &mVariableModuleGlobal
->NonVolatileLastVariableOffset
,
3348 ASSERT_EFI_ERROR (Status
);
3353 Init non-volatile variable store.
3355 @retval EFI_SUCCESS Function successfully executed.
3356 @retval EFI_OUT_OF_RESOURCES Fail to allocate enough memory resource.
3357 @retval EFI_VOLUME_CORRUPTED Variable Store or Firmware Volume for Variable Store is corrupted.
3361 InitNonVolatileVariableStore (
3365 EFI_FIRMWARE_VOLUME_HEADER
*FvHeader
;
3366 VARIABLE_HEADER
*NextVariable
;
3367 EFI_PHYSICAL_ADDRESS VariableStoreBase
;
3368 UINT64 VariableStoreLength
;
3370 EFI_HOB_GUID_TYPE
*GuidHob
;
3371 EFI_PHYSICAL_ADDRESS NvStorageBase
;
3372 UINT8
*NvStorageData
;
3373 UINT32 NvStorageSize
;
3374 FAULT_TOLERANT_WRITE_LAST_WRITE_DATA
*FtwLastWriteData
;
3375 UINT32 BackUpOffset
;
3378 mVariableModuleGlobal
->FvbInstance
= NULL
;
3381 // Note that in EdkII variable driver implementation, Hardware Error Record type variable
3382 // is stored with common variable in the same NV region. So the platform integrator should
3383 // ensure that the value of PcdHwErrStorageSize is less than or equal to the value of
3384 // PcdFlashNvStorageVariableSize.
3386 ASSERT (PcdGet32 (PcdHwErrStorageSize
) <= PcdGet32 (PcdFlashNvStorageVariableSize
));
3389 // Allocate runtime memory used for a memory copy of the FLASH region.
3390 // Keep the memory and the FLASH in sync as updates occur.
3392 NvStorageSize
= PcdGet32 (PcdFlashNvStorageVariableSize
);
3393 NvStorageData
= AllocateRuntimeZeroPool (NvStorageSize
);
3394 if (NvStorageData
== NULL
) {
3395 return EFI_OUT_OF_RESOURCES
;
3398 NvStorageBase
= (EFI_PHYSICAL_ADDRESS
) PcdGet64 (PcdFlashNvStorageVariableBase64
);
3399 if (NvStorageBase
== 0) {
3400 NvStorageBase
= (EFI_PHYSICAL_ADDRESS
) PcdGet32 (PcdFlashNvStorageVariableBase
);
3403 // Copy NV storage data to the memory buffer.
3405 CopyMem (NvStorageData
, (UINT8
*) (UINTN
) NvStorageBase
, NvStorageSize
);
3408 // Check the FTW last write data hob.
3410 GuidHob
= GetFirstGuidHob (&gEdkiiFaultTolerantWriteGuid
);
3411 if (GuidHob
!= NULL
) {
3412 FtwLastWriteData
= (FAULT_TOLERANT_WRITE_LAST_WRITE_DATA
*) GET_GUID_HOB_DATA (GuidHob
);
3413 if (FtwLastWriteData
->TargetAddress
== NvStorageBase
) {
3414 DEBUG ((EFI_D_INFO
, "Variable: NV storage is backed up in spare block: 0x%x\n", (UINTN
) FtwLastWriteData
->SpareAddress
));
3416 // Copy the backed up NV storage data to the memory buffer from spare block.
3418 CopyMem (NvStorageData
, (UINT8
*) (UINTN
) (FtwLastWriteData
->SpareAddress
), NvStorageSize
);
3419 } else if ((FtwLastWriteData
->TargetAddress
> NvStorageBase
) &&
3420 (FtwLastWriteData
->TargetAddress
< (NvStorageBase
+ NvStorageSize
))) {
3422 // Flash NV storage from the Offset is backed up in spare block.
3424 BackUpOffset
= (UINT32
) (FtwLastWriteData
->TargetAddress
- NvStorageBase
);
3425 BackUpSize
= NvStorageSize
- BackUpOffset
;
3426 DEBUG ((EFI_D_INFO
, "Variable: High partial NV storage from offset: %x is backed up in spare block: 0x%x\n", BackUpOffset
, (UINTN
) FtwLastWriteData
->SpareAddress
));
3428 // Copy the partial backed up NV storage data to the memory buffer from spare block.
3430 CopyMem (NvStorageData
+ BackUpOffset
, (UINT8
*) (UINTN
) FtwLastWriteData
->SpareAddress
, BackUpSize
);
3434 FvHeader
= (EFI_FIRMWARE_VOLUME_HEADER
*) NvStorageData
;
3437 // Check if the Firmware Volume is not corrupted
3439 if ((FvHeader
->Signature
!= EFI_FVH_SIGNATURE
) || (!CompareGuid (&gEfiSystemNvDataFvGuid
, &FvHeader
->FileSystemGuid
))) {
3440 FreePool (NvStorageData
);
3441 DEBUG ((EFI_D_ERROR
, "Firmware Volume for Variable Store is corrupted\n"));
3442 return EFI_VOLUME_CORRUPTED
;
3445 VariableStoreBase
= (EFI_PHYSICAL_ADDRESS
) ((UINTN
) FvHeader
+ FvHeader
->HeaderLength
);
3446 VariableStoreLength
= (UINT64
) (NvStorageSize
- FvHeader
->HeaderLength
);
3448 mVariableModuleGlobal
->VariableGlobal
.NonVolatileVariableBase
= VariableStoreBase
;
3449 mNvVariableCache
= (VARIABLE_STORE_HEADER
*) (UINTN
) VariableStoreBase
;
3450 if (GetVariableStoreStatus (mNvVariableCache
) != EfiValid
) {
3451 FreePool (NvStorageData
);
3452 DEBUG((EFI_D_ERROR
, "Variable Store header is corrupted\n"));
3453 return EFI_VOLUME_CORRUPTED
;
3455 ASSERT(mNvVariableCache
->Size
== VariableStoreLength
);
3458 // The max variable or hardware error variable size should be < variable store size.
3460 ASSERT(MAX (PcdGet32 (PcdMaxVariableSize
), PcdGet32 (PcdMaxHardwareErrorVariableSize
)) < VariableStoreLength
);
3463 // Parse non-volatile variable data and get last variable offset.
3465 NextVariable
= GetStartPointer ((VARIABLE_STORE_HEADER
*)(UINTN
)VariableStoreBase
);
3466 while (IsValidVariableHeader (NextVariable
, GetEndPointer ((VARIABLE_STORE_HEADER
*)(UINTN
)VariableStoreBase
))) {
3467 VariableSize
= NextVariable
->NameSize
+ NextVariable
->DataSize
+ sizeof (VARIABLE_HEADER
);
3468 if ((NextVariable
->Attributes
& (EFI_VARIABLE_NON_VOLATILE
| EFI_VARIABLE_HARDWARE_ERROR_RECORD
)) == (EFI_VARIABLE_NON_VOLATILE
| EFI_VARIABLE_HARDWARE_ERROR_RECORD
)) {
3469 mVariableModuleGlobal
->HwErrVariableTotalSize
+= HEADER_ALIGN (VariableSize
);
3471 mVariableModuleGlobal
->CommonVariableTotalSize
+= HEADER_ALIGN (VariableSize
);
3474 NextVariable
= GetNextVariablePtr (NextVariable
);
3476 mVariableModuleGlobal
->NonVolatileLastVariableOffset
= (UINTN
) NextVariable
- (UINTN
) VariableStoreBase
;
3482 Flush the HOB variable to flash.
3484 @param[in] VariableName Name of variable has been updated or deleted.
3485 @param[in] VendorGuid Guid of variable has been updated or deleted.
3489 FlushHobVariableToFlash (
3490 IN CHAR16
*VariableName
,
3491 IN EFI_GUID
*VendorGuid
3495 VARIABLE_STORE_HEADER
*VariableStoreHeader
;
3496 VARIABLE_HEADER
*Variable
;
3503 // Flush the HOB variable to flash.
3505 if (mVariableModuleGlobal
->VariableGlobal
.HobVariableBase
!= 0) {
3506 VariableStoreHeader
= (VARIABLE_STORE_HEADER
*) (UINTN
) mVariableModuleGlobal
->VariableGlobal
.HobVariableBase
;
3508 // Set HobVariableBase to 0, it can avoid SetVariable to call back.
3510 mVariableModuleGlobal
->VariableGlobal
.HobVariableBase
= 0;
3511 for ( Variable
= GetStartPointer (VariableStoreHeader
)
3512 ; IsValidVariableHeader (Variable
, GetEndPointer (VariableStoreHeader
))
3513 ; Variable
= GetNextVariablePtr (Variable
)
3515 if (Variable
->State
!= VAR_ADDED
) {
3517 // The HOB variable has been set to DELETED state in local.
3521 ASSERT ((Variable
->Attributes
& EFI_VARIABLE_NON_VOLATILE
) != 0);
3522 if (VendorGuid
== NULL
|| VariableName
== NULL
||
3523 !CompareGuid (VendorGuid
, &Variable
->VendorGuid
) ||
3524 StrCmp (VariableName
, GetVariableNamePtr (Variable
)) != 0) {
3525 VariableData
= GetVariableDataPtr (Variable
);
3526 Status
= VariableServiceSetVariable (
3527 GetVariableNamePtr (Variable
),
3528 &Variable
->VendorGuid
,
3529 Variable
->Attributes
,
3533 DEBUG ((EFI_D_INFO
, "Variable driver flush the HOB variable to flash: %g %s %r\n", &Variable
->VendorGuid
, GetVariableNamePtr (Variable
), Status
));
3536 // The updated or deleted variable is matched with the HOB variable.
3537 // Don't break here because we will try to set other HOB variables
3538 // since this variable could be set successfully.
3540 Status
= EFI_SUCCESS
;
3542 if (!EFI_ERROR (Status
)) {
3544 // If set variable successful, or the updated or deleted variable is matched with the HOB variable,
3545 // set the HOB variable to DELETED state in local.
3547 DEBUG ((EFI_D_INFO
, "Variable driver set the HOB variable to DELETED state in local: %g %s\n", &Variable
->VendorGuid
, GetVariableNamePtr (Variable
)));
3548 Variable
->State
&= VAR_DELETED
;
3555 // We still have HOB variable(s) not flushed in flash.
3557 mVariableModuleGlobal
->VariableGlobal
.HobVariableBase
= (EFI_PHYSICAL_ADDRESS
) (UINTN
) VariableStoreHeader
;
3560 // All HOB variables have been flushed in flash.
3562 DEBUG ((EFI_D_INFO
, "Variable driver: all HOB variables have been flushed in flash.\n"));
3563 if (!AtRuntime ()) {
3564 FreePool ((VOID
*) VariableStoreHeader
);
3572 Initializes variable write service after FTW was ready.
3574 @retval EFI_SUCCESS Function successfully executed.
3575 @retval Others Fail to initialize the variable service.
3579 VariableWriteServiceInitialize (
3584 VARIABLE_STORE_HEADER
*VariableStoreHeader
;
3587 EFI_PHYSICAL_ADDRESS VariableStoreBase
;
3588 EFI_PHYSICAL_ADDRESS NvStorageBase
;
3590 NvStorageBase
= (EFI_PHYSICAL_ADDRESS
) PcdGet64 (PcdFlashNvStorageVariableBase64
);
3591 if (NvStorageBase
== 0) {
3592 NvStorageBase
= (EFI_PHYSICAL_ADDRESS
) PcdGet32 (PcdFlashNvStorageVariableBase
);
3594 VariableStoreBase
= NvStorageBase
+ (((EFI_FIRMWARE_VOLUME_HEADER
*)(UINTN
)(NvStorageBase
))->HeaderLength
);
3597 // Let NonVolatileVariableBase point to flash variable store base directly after FTW ready.
3599 mVariableModuleGlobal
->VariableGlobal
.NonVolatileVariableBase
= VariableStoreBase
;
3600 VariableStoreHeader
= (VARIABLE_STORE_HEADER
*)(UINTN
)VariableStoreBase
;
3603 // Check if the free area is really free.
3605 for (Index
= mVariableModuleGlobal
->NonVolatileLastVariableOffset
; Index
< VariableStoreHeader
->Size
; Index
++) {
3606 Data
= ((UINT8
*) mNvVariableCache
)[Index
];
3609 // There must be something wrong in variable store, do reclaim operation.
3612 mVariableModuleGlobal
->VariableGlobal
.NonVolatileVariableBase
,
3613 &mVariableModuleGlobal
->NonVolatileLastVariableOffset
,
3620 if (EFI_ERROR (Status
)) {
3627 FlushHobVariableToFlash (NULL
, NULL
);
3630 // Authenticated variable initialize.
3632 Status
= AutenticatedVariableServiceInitialize ();
3639 Initializes variable store area for non-volatile and volatile variable.
3641 @retval EFI_SUCCESS Function successfully executed.
3642 @retval EFI_OUT_OF_RESOURCES Fail to allocate enough memory resource.
3646 VariableCommonInitialize (
3651 VARIABLE_STORE_HEADER
*VolatileVariableStore
;
3652 VARIABLE_STORE_HEADER
*VariableStoreHeader
;
3653 UINT64 VariableStoreLength
;
3655 EFI_HOB_GUID_TYPE
*GuidHob
;
3658 // Allocate runtime memory for variable driver global structure.
3660 mVariableModuleGlobal
= AllocateRuntimeZeroPool (sizeof (VARIABLE_MODULE_GLOBAL
));
3661 if (mVariableModuleGlobal
== NULL
) {
3662 return EFI_OUT_OF_RESOURCES
;
3665 InitializeLock (&mVariableModuleGlobal
->VariableGlobal
.VariableServicesLock
, TPL_NOTIFY
);
3668 // Get HOB variable store.
3670 GuidHob
= GetFirstGuidHob (&gEfiAuthenticatedVariableGuid
);
3671 if (GuidHob
!= NULL
) {
3672 VariableStoreHeader
= GET_GUID_HOB_DATA (GuidHob
);
3673 VariableStoreLength
= (UINT64
) (GuidHob
->Header
.HobLength
- sizeof (EFI_HOB_GUID_TYPE
));
3674 if (GetVariableStoreStatus (VariableStoreHeader
) == EfiValid
) {
3675 mVariableModuleGlobal
->VariableGlobal
.HobVariableBase
= (EFI_PHYSICAL_ADDRESS
) (UINTN
) AllocateRuntimeCopyPool ((UINTN
) VariableStoreLength
, (VOID
*) VariableStoreHeader
);
3676 if (mVariableModuleGlobal
->VariableGlobal
.HobVariableBase
== 0) {
3677 FreePool (mVariableModuleGlobal
);
3678 return EFI_OUT_OF_RESOURCES
;
3681 DEBUG ((EFI_D_ERROR
, "HOB Variable Store header is corrupted!\n"));
3686 // Allocate memory for volatile variable store, note that there is a scratch space to store scratch data.
3688 ScratchSize
= MAX (PcdGet32 (PcdMaxVariableSize
), PcdGet32 (PcdMaxHardwareErrorVariableSize
));
3689 VolatileVariableStore
= AllocateRuntimePool (PcdGet32 (PcdVariableStoreSize
) + ScratchSize
);
3690 if (VolatileVariableStore
== NULL
) {
3691 if (mVariableModuleGlobal
->VariableGlobal
.HobVariableBase
!= 0) {
3692 FreePool ((VOID
*) (UINTN
) mVariableModuleGlobal
->VariableGlobal
.HobVariableBase
);
3694 FreePool (mVariableModuleGlobal
);
3695 return EFI_OUT_OF_RESOURCES
;
3698 SetMem (VolatileVariableStore
, PcdGet32 (PcdVariableStoreSize
) + ScratchSize
, 0xff);
3701 // Initialize Variable Specific Data.
3703 mVariableModuleGlobal
->VariableGlobal
.VolatileVariableBase
= (EFI_PHYSICAL_ADDRESS
) (UINTN
) VolatileVariableStore
;
3704 mVariableModuleGlobal
->VolatileLastVariableOffset
= (UINTN
) GetStartPointer (VolatileVariableStore
) - (UINTN
) VolatileVariableStore
;
3706 CopyGuid (&VolatileVariableStore
->Signature
, &gEfiAuthenticatedVariableGuid
);
3707 VolatileVariableStore
->Size
= PcdGet32 (PcdVariableStoreSize
);
3708 VolatileVariableStore
->Format
= VARIABLE_STORE_FORMATTED
;
3709 VolatileVariableStore
->State
= VARIABLE_STORE_HEALTHY
;
3710 VolatileVariableStore
->Reserved
= 0;
3711 VolatileVariableStore
->Reserved1
= 0;
3714 // Init non-volatile variable store.
3716 Status
= InitNonVolatileVariableStore ();
3717 if (EFI_ERROR (Status
)) {
3718 if (mVariableModuleGlobal
->VariableGlobal
.HobVariableBase
!= 0) {
3719 FreePool ((VOID
*) (UINTN
) mVariableModuleGlobal
->VariableGlobal
.HobVariableBase
);
3721 FreePool (mVariableModuleGlobal
);
3722 FreePool (VolatileVariableStore
);
3730 Get the proper fvb handle and/or fvb protocol by the given Flash address.
3732 @param[in] Address The Flash address.
3733 @param[out] FvbHandle In output, if it is not NULL, it points to the proper FVB handle.
3734 @param[out] FvbProtocol In output, if it is not NULL, it points to the proper FVB protocol.
3738 GetFvbInfoByAddress (
3739 IN EFI_PHYSICAL_ADDRESS Address
,
3740 OUT EFI_HANDLE
*FvbHandle OPTIONAL
,
3741 OUT EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
**FvbProtocol OPTIONAL
3745 EFI_HANDLE
*HandleBuffer
;
3748 EFI_PHYSICAL_ADDRESS FvbBaseAddress
;
3749 EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*Fvb
;
3750 EFI_FVB_ATTRIBUTES_2 Attributes
;
3752 UINTN NumberOfBlocks
;
3754 HandleBuffer
= NULL
;
3756 // Get all FVB handles.
3758 Status
= GetFvbCountAndBuffer (&HandleCount
, &HandleBuffer
);
3759 if (EFI_ERROR (Status
)) {
3760 return EFI_NOT_FOUND
;
3764 // Get the FVB to access variable store.
3767 for (Index
= 0; Index
< HandleCount
; Index
+= 1, Status
= EFI_NOT_FOUND
, Fvb
= NULL
) {
3768 Status
= GetFvbByHandle (HandleBuffer
[Index
], &Fvb
);
3769 if (EFI_ERROR (Status
)) {
3770 Status
= EFI_NOT_FOUND
;
3775 // Ensure this FVB protocol supported Write operation.
3777 Status
= Fvb
->GetAttributes (Fvb
, &Attributes
);
3778 if (EFI_ERROR (Status
) || ((Attributes
& EFI_FVB2_WRITE_STATUS
) == 0)) {
3783 // Compare the address and select the right one.
3785 Status
= Fvb
->GetPhysicalAddress (Fvb
, &FvbBaseAddress
);
3786 if (EFI_ERROR (Status
)) {
3791 // Assume one FVB has one type of BlockSize.
3793 Status
= Fvb
->GetBlockSize (Fvb
, 0, &BlockSize
, &NumberOfBlocks
);
3794 if (EFI_ERROR (Status
)) {
3798 if ((Address
>= FvbBaseAddress
) && (Address
< (FvbBaseAddress
+ BlockSize
* NumberOfBlocks
))) {
3799 if (FvbHandle
!= NULL
) {
3800 *FvbHandle
= HandleBuffer
[Index
];
3802 if (FvbProtocol
!= NULL
) {
3805 Status
= EFI_SUCCESS
;
3809 FreePool (HandleBuffer
);
3812 Status
= EFI_NOT_FOUND
;