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 - 2014, 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
;
62 // To prevent name collisions with possible future globally defined variables,
63 // other internal firmware data variables that are not defined here must be
64 // saved with a unique VendorGuid other than EFI_GLOBAL_VARIABLE or
65 // any other GUID defined by the UEFI Specification. Implementations must
66 // only permit the creation of variables with a UEFI Specification-defined
67 // VendorGuid when these variables are documented in the UEFI Specification.
69 GLOBAL_VARIABLE_ENTRY mGlobalVariableList
[] = {
70 {EFI_LANG_CODES_VARIABLE_NAME
, VARIABLE_ATTRIBUTE_BS_RT
},
71 {EFI_LANG_VARIABLE_NAME
, VARIABLE_ATTRIBUTE_NV_BS_RT
},
72 {EFI_TIME_OUT_VARIABLE_NAME
, VARIABLE_ATTRIBUTE_NV_BS_RT
},
73 {EFI_PLATFORM_LANG_CODES_VARIABLE_NAME
, VARIABLE_ATTRIBUTE_BS_RT
},
74 {EFI_PLATFORM_LANG_VARIABLE_NAME
, VARIABLE_ATTRIBUTE_NV_BS_RT
},
75 {EFI_CON_IN_VARIABLE_NAME
, VARIABLE_ATTRIBUTE_NV_BS_RT
},
76 {EFI_CON_OUT_VARIABLE_NAME
, VARIABLE_ATTRIBUTE_NV_BS_RT
},
77 {EFI_ERR_OUT_VARIABLE_NAME
, VARIABLE_ATTRIBUTE_NV_BS_RT
},
78 {EFI_CON_IN_DEV_VARIABLE_NAME
, VARIABLE_ATTRIBUTE_BS_RT
},
79 {EFI_CON_OUT_DEV_VARIABLE_NAME
, VARIABLE_ATTRIBUTE_BS_RT
},
80 {EFI_ERR_OUT_DEV_VARIABLE_NAME
, VARIABLE_ATTRIBUTE_BS_RT
},
81 {EFI_BOOT_ORDER_VARIABLE_NAME
, VARIABLE_ATTRIBUTE_NV_BS_RT
},
82 {EFI_BOOT_NEXT_VARIABLE_NAME
, VARIABLE_ATTRIBUTE_NV_BS_RT
},
83 {EFI_BOOT_CURRENT_VARIABLE_NAME
, VARIABLE_ATTRIBUTE_BS_RT
},
84 {EFI_BOOT_OPTION_SUPPORT_VARIABLE_NAME
, VARIABLE_ATTRIBUTE_BS_RT
},
85 {EFI_DRIVER_ORDER_VARIABLE_NAME
, VARIABLE_ATTRIBUTE_NV_BS_RT
},
86 {EFI_HW_ERR_REC_SUPPORT_VARIABLE_NAME
, VARIABLE_ATTRIBUTE_NV_BS_RT
},
87 {EFI_SETUP_MODE_NAME
, VARIABLE_ATTRIBUTE_BS_RT
},
88 {EFI_KEY_EXCHANGE_KEY_NAME
, VARIABLE_ATTRIBUTE_NV_BS_RT_AT
},
89 {EFI_PLATFORM_KEY_NAME
, VARIABLE_ATTRIBUTE_NV_BS_RT_AT
},
90 {EFI_SIGNATURE_SUPPORT_NAME
, VARIABLE_ATTRIBUTE_BS_RT
},
91 {EFI_SECURE_BOOT_MODE_NAME
, VARIABLE_ATTRIBUTE_BS_RT
},
92 {EFI_KEK_DEFAULT_VARIABLE_NAME
, VARIABLE_ATTRIBUTE_BS_RT
},
93 {EFI_PK_DEFAULT_VARIABLE_NAME
, VARIABLE_ATTRIBUTE_BS_RT
},
94 {EFI_DB_DEFAULT_VARIABLE_NAME
, VARIABLE_ATTRIBUTE_BS_RT
},
95 {EFI_DBX_DEFAULT_VARIABLE_NAME
, VARIABLE_ATTRIBUTE_BS_RT
},
96 {EFI_DBT_DEFAULT_VARIABLE_NAME
, VARIABLE_ATTRIBUTE_BS_RT
},
97 {EFI_OS_INDICATIONS_SUPPORT_VARIABLE_NAME
, VARIABLE_ATTRIBUTE_BS_RT
},
98 {EFI_OS_INDICATIONS_VARIABLE_NAME
, VARIABLE_ATTRIBUTE_NV_BS_RT
},
99 {EFI_VENDOR_KEYS_VARIABLE_NAME
, VARIABLE_ATTRIBUTE_BS_RT
},
101 GLOBAL_VARIABLE_ENTRY mGlobalVariableList2
[] = {
102 {L
"Boot####", VARIABLE_ATTRIBUTE_NV_BS_RT
},
103 {L
"Driver####", VARIABLE_ATTRIBUTE_NV_BS_RT
},
104 {L
"Key####", VARIABLE_ATTRIBUTE_NV_BS_RT
},
109 SecureBoot Hook for auth variable update.
111 @param[in] VariableName Name of Variable to be found.
112 @param[in] VendorGuid Variable vendor GUID.
117 IN CHAR16
*VariableName
,
118 IN EFI_GUID
*VendorGuid
122 Routine used to track statistical information about variable usage.
123 The data is stored in the EFI system table so it can be accessed later.
124 VariableInfo.efi can dump out the table. Only Boot Services variable
125 accesses are tracked by this code. The PcdVariableCollectStatistics
126 build flag controls if this feature is enabled.
128 A read that hits in the cache will have Read and Cache true for
129 the transaction. Data is allocated by this routine, but never
132 @param[in] VariableName Name of the Variable to track.
133 @param[in] VendorGuid Guid of the Variable to track.
134 @param[in] Volatile TRUE if volatile FALSE if non-volatile.
135 @param[in] Read TRUE if GetVariable() was called.
136 @param[in] Write TRUE if SetVariable() was called.
137 @param[in] Delete TRUE if deleted via SetVariable().
138 @param[in] Cache TRUE for a cache hit.
143 IN CHAR16
*VariableName
,
144 IN EFI_GUID
*VendorGuid
,
152 VARIABLE_INFO_ENTRY
*Entry
;
154 if (FeaturePcdGet (PcdVariableCollectStatistics
)) {
157 // Don't collect statistics at runtime.
161 if (gVariableInfo
== NULL
) {
163 // On the first call allocate a entry and place a pointer to it in
164 // the EFI System Table.
166 gVariableInfo
= AllocateZeroPool (sizeof (VARIABLE_INFO_ENTRY
));
167 ASSERT (gVariableInfo
!= NULL
);
169 CopyGuid (&gVariableInfo
->VendorGuid
, VendorGuid
);
170 gVariableInfo
->Name
= AllocatePool (StrSize (VariableName
));
171 ASSERT (gVariableInfo
->Name
!= NULL
);
172 StrCpy (gVariableInfo
->Name
, VariableName
);
173 gVariableInfo
->Volatile
= Volatile
;
177 for (Entry
= gVariableInfo
; Entry
!= NULL
; Entry
= Entry
->Next
) {
178 if (CompareGuid (VendorGuid
, &Entry
->VendorGuid
)) {
179 if (StrCmp (VariableName
, Entry
->Name
) == 0) {
187 Entry
->DeleteCount
++;
197 if (Entry
->Next
== NULL
) {
199 // If the entry is not in the table add it.
200 // Next iteration of the loop will fill in the data.
202 Entry
->Next
= AllocateZeroPool (sizeof (VARIABLE_INFO_ENTRY
));
203 ASSERT (Entry
->Next
!= NULL
);
205 CopyGuid (&Entry
->Next
->VendorGuid
, VendorGuid
);
206 Entry
->Next
->Name
= AllocatePool (StrSize (VariableName
));
207 ASSERT (Entry
->Next
->Name
!= NULL
);
208 StrCpy (Entry
->Next
->Name
, VariableName
);
209 Entry
->Next
->Volatile
= Volatile
;
219 This code checks if variable header is valid or not.
221 @param Variable Pointer to the Variable Header.
223 @retval TRUE Variable header is valid.
224 @retval FALSE Variable header is not valid.
228 IsValidVariableHeader (
229 IN VARIABLE_HEADER
*Variable
232 if (Variable
== NULL
|| Variable
->StartId
!= VARIABLE_DATA
) {
242 This function writes data to the FWH at the correct LBA even if the LBAs
245 @param Global Pointer to VARAIBLE_GLOBAL structure.
246 @param Volatile Point out the Variable is Volatile or Non-Volatile.
247 @param SetByIndex TRUE if target pointer is given as index.
248 FALSE if target pointer is absolute.
249 @param Fvb Pointer to the writable FVB protocol.
250 @param DataPtrIndex Pointer to the Data from the end of VARIABLE_STORE_HEADER
252 @param DataSize Size of data to be written.
253 @param Buffer Pointer to the buffer from which data is written.
255 @retval EFI_INVALID_PARAMETER Parameters not valid.
256 @retval EFI_SUCCESS Variable store successfully updated.
260 UpdateVariableStore (
261 IN VARIABLE_GLOBAL
*Global
,
263 IN BOOLEAN SetByIndex
,
264 IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*Fvb
,
265 IN UINTN DataPtrIndex
,
270 EFI_FV_BLOCK_MAP_ENTRY
*PtrBlockMapEntry
;
278 EFI_FIRMWARE_VOLUME_HEADER
*FwVolHeader
;
279 VARIABLE_STORE_HEADER
*VolatileBase
;
280 EFI_PHYSICAL_ADDRESS FvVolHdr
;
281 EFI_PHYSICAL_ADDRESS DataPtr
;
285 DataPtr
= DataPtrIndex
;
288 // Check if the Data is Volatile.
292 return EFI_INVALID_PARAMETER
;
294 Status
= Fvb
->GetPhysicalAddress(Fvb
, &FvVolHdr
);
295 ASSERT_EFI_ERROR (Status
);
297 FwVolHeader
= (EFI_FIRMWARE_VOLUME_HEADER
*) ((UINTN
) FvVolHdr
);
299 // Data Pointer should point to the actual Address where data is to be
303 DataPtr
+= mVariableModuleGlobal
->VariableGlobal
.NonVolatileVariableBase
;
306 if ((DataPtr
+ DataSize
) >= ((EFI_PHYSICAL_ADDRESS
) (UINTN
) ((UINT8
*) FwVolHeader
+ FwVolHeader
->FvLength
))) {
307 return EFI_INVALID_PARAMETER
;
311 // Data Pointer should point to the actual Address where data is to be
314 VolatileBase
= (VARIABLE_STORE_HEADER
*) ((UINTN
) mVariableModuleGlobal
->VariableGlobal
.VolatileVariableBase
);
316 DataPtr
+= mVariableModuleGlobal
->VariableGlobal
.VolatileVariableBase
;
319 if ((DataPtr
+ DataSize
) >= ((UINTN
) ((UINT8
*) VolatileBase
+ VolatileBase
->Size
))) {
320 return EFI_INVALID_PARAMETER
;
324 // If Volatile Variable just do a simple mem copy.
326 CopyMem ((UINT8
*)(UINTN
)DataPtr
, Buffer
, DataSize
);
331 // If we are here we are dealing with Non-Volatile Variables.
333 LinearOffset
= (UINTN
) FwVolHeader
;
334 CurrWritePtr
= (UINTN
) DataPtr
;
335 CurrWriteSize
= DataSize
;
339 if (CurrWritePtr
< LinearOffset
) {
340 return EFI_INVALID_PARAMETER
;
343 for (PtrBlockMapEntry
= FwVolHeader
->BlockMap
; PtrBlockMapEntry
->NumBlocks
!= 0; PtrBlockMapEntry
++) {
344 for (BlockIndex2
= 0; BlockIndex2
< PtrBlockMapEntry
->NumBlocks
; BlockIndex2
++) {
346 // Check to see if the Variable Writes are spanning through multiple
349 if ((CurrWritePtr
>= LinearOffset
) && (CurrWritePtr
< LinearOffset
+ PtrBlockMapEntry
->Length
)) {
350 if ((CurrWritePtr
+ CurrWriteSize
) <= (LinearOffset
+ PtrBlockMapEntry
->Length
)) {
351 Status
= Fvb
->Write (
354 (UINTN
) (CurrWritePtr
- LinearOffset
),
360 Size
= (UINT32
) (LinearOffset
+ PtrBlockMapEntry
->Length
- CurrWritePtr
);
361 Status
= Fvb
->Write (
364 (UINTN
) (CurrWritePtr
- LinearOffset
),
368 if (EFI_ERROR (Status
)) {
372 CurrWritePtr
= LinearOffset
+ PtrBlockMapEntry
->Length
;
373 CurrBuffer
= CurrBuffer
+ Size
;
374 CurrWriteSize
= CurrWriteSize
- Size
;
378 LinearOffset
+= PtrBlockMapEntry
->Length
;
389 This code gets the current status of Variable Store.
391 @param VarStoreHeader Pointer to the Variable Store Header.
393 @retval EfiRaw Variable store status is raw.
394 @retval EfiValid Variable store status is valid.
395 @retval EfiInvalid Variable store status is invalid.
398 VARIABLE_STORE_STATUS
399 GetVariableStoreStatus (
400 IN VARIABLE_STORE_HEADER
*VarStoreHeader
403 if (CompareGuid (&VarStoreHeader
->Signature
, &gEfiAuthenticatedVariableGuid
) &&
404 VarStoreHeader
->Format
== VARIABLE_STORE_FORMATTED
&&
405 VarStoreHeader
->State
== VARIABLE_STORE_HEALTHY
409 } else if (((UINT32
*)(&VarStoreHeader
->Signature
))[0] == 0xffffffff &&
410 ((UINT32
*)(&VarStoreHeader
->Signature
))[1] == 0xffffffff &&
411 ((UINT32
*)(&VarStoreHeader
->Signature
))[2] == 0xffffffff &&
412 ((UINT32
*)(&VarStoreHeader
->Signature
))[3] == 0xffffffff &&
413 VarStoreHeader
->Size
== 0xffffffff &&
414 VarStoreHeader
->Format
== 0xff &&
415 VarStoreHeader
->State
== 0xff
427 This code gets the size of name of variable.
429 @param Variable Pointer to the Variable Header.
431 @return UINTN Size of variable in bytes.
436 IN VARIABLE_HEADER
*Variable
439 if (Variable
->State
== (UINT8
) (-1) ||
440 Variable
->DataSize
== (UINT32
) (-1) ||
441 Variable
->NameSize
== (UINT32
) (-1) ||
442 Variable
->Attributes
== (UINT32
) (-1)) {
445 return (UINTN
) Variable
->NameSize
;
450 This code gets the size of variable data.
452 @param Variable Pointer to the Variable Header.
454 @return Size of variable in bytes.
459 IN VARIABLE_HEADER
*Variable
462 if (Variable
->State
== (UINT8
) (-1) ||
463 Variable
->DataSize
== (UINT32
) (-1) ||
464 Variable
->NameSize
== (UINT32
) (-1) ||
465 Variable
->Attributes
== (UINT32
) (-1)) {
468 return (UINTN
) Variable
->DataSize
;
473 This code gets the pointer to the variable name.
475 @param Variable Pointer to the Variable Header.
477 @return Pointer to Variable Name which is Unicode encoding.
482 IN VARIABLE_HEADER
*Variable
486 return (CHAR16
*) (Variable
+ 1);
491 This code gets the pointer to the variable data.
493 @param Variable Pointer to the Variable Header.
495 @return Pointer to Variable Data.
500 IN VARIABLE_HEADER
*Variable
506 // Be careful about pad size for alignment.
508 Value
= (UINTN
) GetVariableNamePtr (Variable
);
509 Value
+= NameSizeOfVariable (Variable
);
510 Value
+= GET_PAD_SIZE (NameSizeOfVariable (Variable
));
512 return (UINT8
*) Value
;
518 This code gets the pointer to the next variable header.
520 @param Variable Pointer to the Variable Header.
522 @return Pointer to next variable header.
527 IN VARIABLE_HEADER
*Variable
532 if (!IsValidVariableHeader (Variable
)) {
536 Value
= (UINTN
) GetVariableDataPtr (Variable
);
537 Value
+= DataSizeOfVariable (Variable
);
538 Value
+= GET_PAD_SIZE (DataSizeOfVariable (Variable
));
541 // Be careful about pad size for alignment.
543 return (VARIABLE_HEADER
*) HEADER_ALIGN (Value
);
548 Gets the pointer to the first variable header in given variable store area.
550 @param VarStoreHeader Pointer to the Variable Store Header.
552 @return Pointer to the first variable header.
557 IN VARIABLE_STORE_HEADER
*VarStoreHeader
561 // The end of variable store.
563 return (VARIABLE_HEADER
*) HEADER_ALIGN (VarStoreHeader
+ 1);
568 Gets the pointer to the end of the variable storage area.
570 This function gets pointer to the end of the variable storage
571 area, according to the input variable store header.
573 @param VarStoreHeader Pointer to the Variable Store Header.
575 @return Pointer to the end of the variable storage area.
580 IN VARIABLE_STORE_HEADER
*VarStoreHeader
584 // The end of variable store
586 return (VARIABLE_HEADER
*) HEADER_ALIGN ((UINTN
) VarStoreHeader
+ VarStoreHeader
->Size
);
591 Check the PubKeyIndex is a valid key or not.
593 This function will iterate the NV storage to see if this PubKeyIndex is still referenced
594 by any valid count-based auth variabe.
596 @param[in] PubKeyIndex Index of the public key in public key store.
598 @retval TRUE The PubKeyIndex is still in use.
599 @retval FALSE The PubKeyIndex is not referenced by any count-based auth variabe.
604 IN UINT32 PubKeyIndex
607 VARIABLE_HEADER
*Variable
;
609 if (PubKeyIndex
> mPubKeyNumber
) {
613 Variable
= GetStartPointer (mNvVariableCache
);
615 while (IsValidVariableHeader (Variable
)) {
616 if ((Variable
->State
== VAR_ADDED
|| Variable
->State
== (VAR_IN_DELETED_TRANSITION
& VAR_ADDED
)) &&
617 Variable
->PubKeyIndex
== PubKeyIndex
) {
620 Variable
= GetNextVariablePtr (Variable
);
628 Get the number of valid public key in PubKeyStore.
630 @param[in] PubKeyNumber Number of the public key in public key store.
632 @return Number of valid public key in PubKeyStore.
636 GetValidPubKeyNumber (
637 IN UINT32 PubKeyNumber
645 for (PubKeyIndex
= 1; PubKeyIndex
<= PubKeyNumber
; PubKeyIndex
++) {
646 if (IsValidPubKeyIndex (PubKeyIndex
)) {
656 Filter the useless key in public key store.
658 This function will find out all valid public keys in public key database, save them in new allocated
659 buffer NewPubKeyStore, and give the new PubKeyIndex. The caller is responsible for freeing buffer
660 NewPubKeyIndex and NewPubKeyStore with FreePool().
662 @param[in] PubKeyStore Point to the public key database.
663 @param[in] PubKeyNumber Number of the public key in PubKeyStore.
664 @param[out] NewPubKeyIndex Point to an array of new PubKeyIndex corresponds to NewPubKeyStore.
665 @param[out] NewPubKeyStore Saved all valid public keys in PubKeyStore.
666 @param[out] NewPubKeySize Buffer size of the NewPubKeyStore.
668 @retval EFI_SUCCESS Trim operation is complete successfully.
669 @retval EFI_OUT_OF_RESOURCES No enough memory resources, or no useless key in PubKeyStore.
674 IN UINT8
*PubKeyStore
,
675 IN UINT32 PubKeyNumber
,
676 OUT UINT32
**NewPubKeyIndex
,
677 OUT UINT8
**NewPubKeyStore
,
678 OUT UINT32
*NewPubKeySize
683 UINT32 NewPubKeyNumber
;
685 NewPubKeyNumber
= GetValidPubKeyNumber (PubKeyNumber
);
686 if (NewPubKeyNumber
== PubKeyNumber
) {
687 return EFI_OUT_OF_RESOURCES
;
690 if (NewPubKeyNumber
!= 0) {
691 *NewPubKeySize
= NewPubKeyNumber
* EFI_CERT_TYPE_RSA2048_SIZE
;
693 *NewPubKeySize
= sizeof (UINT8
);
696 *NewPubKeyStore
= AllocatePool (*NewPubKeySize
);
697 if (*NewPubKeyStore
== NULL
) {
698 return EFI_OUT_OF_RESOURCES
;
701 *NewPubKeyIndex
= AllocateZeroPool ((PubKeyNumber
+ 1) * sizeof (UINT32
));
702 if (*NewPubKeyIndex
== NULL
) {
703 FreePool (*NewPubKeyStore
);
704 *NewPubKeyStore
= NULL
;
705 return EFI_OUT_OF_RESOURCES
;
709 for (PubKeyIndex
= 1; PubKeyIndex
<= PubKeyNumber
; PubKeyIndex
++) {
710 if (IsValidPubKeyIndex (PubKeyIndex
)) {
712 *NewPubKeyStore
+ CopiedKey
* EFI_CERT_TYPE_RSA2048_SIZE
,
713 PubKeyStore
+ (PubKeyIndex
- 1) * EFI_CERT_TYPE_RSA2048_SIZE
,
714 EFI_CERT_TYPE_RSA2048_SIZE
716 (*NewPubKeyIndex
)[PubKeyIndex
] = ++CopiedKey
;
724 Variable store garbage collection and reclaim operation.
726 If ReclaimPubKeyStore is FALSE, reclaim variable space by deleting the obsoleted varaibles.
727 If ReclaimPubKeyStore is TRUE, reclaim invalid key in public key database and update the PubKeyIndex
728 for all the count-based authenticate variable in NV storage.
730 @param[in] VariableBase Base address of variable store.
731 @param[out] LastVariableOffset Offset of last variable.
732 @param[in] IsVolatile The variable store is volatile or not;
733 if it is non-volatile, need FTW.
734 @param[in, out] UpdatingPtrTrack Pointer to updating variable pointer track structure.
735 @param[in] NewVariable Pointer to new variable.
736 @param[in] NewVariableSize New variable size.
737 @param[in] ReclaimPubKeyStore Reclaim for public key database or not.
739 @return EFI_SUCCESS Reclaim operation has finished successfully.
740 @return EFI_OUT_OF_RESOURCES No enough memory resources or variable space.
741 @return EFI_DEVICE_ERROR The public key database doesn't exist.
742 @return Others Unexpect error happened during reclaim operation.
747 IN EFI_PHYSICAL_ADDRESS VariableBase
,
748 OUT UINTN
*LastVariableOffset
,
749 IN BOOLEAN IsVolatile
,
750 IN OUT VARIABLE_POINTER_TRACK
*UpdatingPtrTrack
,
751 IN VARIABLE_HEADER
*NewVariable
,
752 IN UINTN NewVariableSize
,
753 IN BOOLEAN ReclaimPubKeyStore
756 VARIABLE_HEADER
*Variable
;
757 VARIABLE_HEADER
*AddedVariable
;
758 VARIABLE_HEADER
*NextVariable
;
759 VARIABLE_HEADER
*NextAddedVariable
;
760 VARIABLE_STORE_HEADER
*VariableStoreHeader
;
762 UINTN MaximumBufferSize
;
770 UINTN CommonVariableTotalSize
;
771 UINTN HwErrVariableTotalSize
;
772 UINT32
*NewPubKeyIndex
;
773 UINT8
*NewPubKeyStore
;
774 UINT32 NewPubKeySize
;
775 VARIABLE_HEADER
*PubKeyHeader
;
776 VARIABLE_HEADER
*UpdatingVariable
;
777 VARIABLE_HEADER
*UpdatingInDeletedTransition
;
779 UpdatingVariable
= NULL
;
780 UpdatingInDeletedTransition
= NULL
;
781 if (UpdatingPtrTrack
!= NULL
) {
782 UpdatingVariable
= UpdatingPtrTrack
->CurrPtr
;
783 UpdatingInDeletedTransition
= UpdatingPtrTrack
->InDeletedTransitionPtr
;
786 VariableStoreHeader
= (VARIABLE_STORE_HEADER
*) ((UINTN
) VariableBase
);
788 CommonVariableTotalSize
= 0;
789 HwErrVariableTotalSize
= 0;
790 NewPubKeyIndex
= NULL
;
791 NewPubKeyStore
= NULL
;
797 // Start Pointers for the variable.
799 Variable
= GetStartPointer (VariableStoreHeader
);
800 MaximumBufferSize
= sizeof (VARIABLE_STORE_HEADER
);
802 while (IsValidVariableHeader (Variable
)) {
803 NextVariable
= GetNextVariablePtr (Variable
);
804 if ((Variable
->State
== VAR_ADDED
|| Variable
->State
== (VAR_IN_DELETED_TRANSITION
& VAR_ADDED
)) &&
805 Variable
!= UpdatingVariable
&&
806 Variable
!= UpdatingInDeletedTransition
808 VariableSize
= (UINTN
) NextVariable
- (UINTN
) Variable
;
809 MaximumBufferSize
+= VariableSize
;
812 Variable
= NextVariable
;
815 if (NewVariable
!= NULL
) {
817 // Add the new variable size.
819 MaximumBufferSize
+= NewVariableSize
;
823 // Reserve the 1 Bytes with Oxff to identify the
824 // end of the variable buffer.
826 MaximumBufferSize
+= 1;
827 ValidBuffer
= AllocatePool (MaximumBufferSize
);
828 if (ValidBuffer
== NULL
) {
829 return EFI_OUT_OF_RESOURCES
;
833 // For NV variable reclaim, don't allocate pool here and just use mNvVariableCache
834 // as the buffer to reduce SMRAM consumption for SMM variable driver.
836 MaximumBufferSize
= mNvVariableCache
->Size
;
837 ValidBuffer
= (UINT8
*) mNvVariableCache
;
840 SetMem (ValidBuffer
, MaximumBufferSize
, 0xff);
843 // Copy variable store header.
845 CopyMem (ValidBuffer
, VariableStoreHeader
, sizeof (VARIABLE_STORE_HEADER
));
846 CurrPtr
= (UINT8
*) GetStartPointer ((VARIABLE_STORE_HEADER
*) ValidBuffer
);
848 if (ReclaimPubKeyStore
) {
849 ASSERT (IsVolatile
== FALSE
);
851 // Trim the PubKeyStore and get new PubKeyIndex.
853 Status
= PubKeyStoreFilter (
860 if (EFI_ERROR (Status
)) {
865 // Refresh the PubKeyIndex for all valid variables (ADDED and IN_DELETED_TRANSITION).
867 Variable
= GetStartPointer (VariableStoreHeader
);
868 while (IsValidVariableHeader (Variable
)) {
869 NextVariable
= GetNextVariablePtr (Variable
);
870 if (Variable
->State
== VAR_ADDED
|| Variable
->State
== (VAR_IN_DELETED_TRANSITION
& VAR_ADDED
)) {
871 if ((StrCmp (GetVariableNamePtr (Variable
), AUTHVAR_KEYDB_NAME
) == 0) &&
872 (CompareGuid (&Variable
->VendorGuid
, &gEfiAuthenticatedVariableGuid
))) {
874 // Skip the public key database, it will be reinstalled later.
876 PubKeyHeader
= Variable
;
877 Variable
= NextVariable
;
881 VariableSize
= (UINTN
) NextVariable
- (UINTN
) Variable
;
882 CopyMem (CurrPtr
, (UINT8
*) Variable
, VariableSize
);
883 ((VARIABLE_HEADER
*) CurrPtr
)->PubKeyIndex
= NewPubKeyIndex
[Variable
->PubKeyIndex
];
884 CurrPtr
+= VariableSize
;
885 if ((Variable
->Attributes
& EFI_VARIABLE_HARDWARE_ERROR_RECORD
) == EFI_VARIABLE_HARDWARE_ERROR_RECORD
) {
886 HwErrVariableTotalSize
+= VariableSize
;
887 } else if ((Variable
->Attributes
& EFI_VARIABLE_HARDWARE_ERROR_RECORD
) != EFI_VARIABLE_HARDWARE_ERROR_RECORD
) {
888 CommonVariableTotalSize
+= VariableSize
;
891 Variable
= NextVariable
;
895 // Reinstall the new public key database.
897 ASSERT (PubKeyHeader
!= NULL
);
898 if (PubKeyHeader
== NULL
) {
899 Status
= EFI_DEVICE_ERROR
;
902 CopyMem (CurrPtr
, (UINT8
*) PubKeyHeader
, sizeof (VARIABLE_HEADER
));
903 Variable
= (VARIABLE_HEADER
*) CurrPtr
;
904 Variable
->DataSize
= NewPubKeySize
;
905 StrCpy (GetVariableNamePtr (Variable
), GetVariableNamePtr (PubKeyHeader
));
906 CopyMem (GetVariableDataPtr (Variable
), NewPubKeyStore
, NewPubKeySize
);
907 CurrPtr
= (UINT8
*) GetNextVariablePtr (Variable
);
908 CommonVariableTotalSize
+= (UINTN
) CurrPtr
- (UINTN
) Variable
;
911 // Reinstall all ADDED variables as long as they are not identical to Updating Variable.
913 Variable
= GetStartPointer (VariableStoreHeader
);
914 while (IsValidVariableHeader (Variable
)) {
915 NextVariable
= GetNextVariablePtr (Variable
);
916 if (Variable
!= UpdatingVariable
&& Variable
->State
== VAR_ADDED
) {
917 VariableSize
= (UINTN
) NextVariable
- (UINTN
) Variable
;
918 CopyMem (CurrPtr
, (UINT8
*) Variable
, VariableSize
);
919 CurrPtr
+= VariableSize
;
920 if ((!IsVolatile
) && ((Variable
->Attributes
& EFI_VARIABLE_HARDWARE_ERROR_RECORD
) == EFI_VARIABLE_HARDWARE_ERROR_RECORD
)) {
921 HwErrVariableTotalSize
+= VariableSize
;
922 } else if ((!IsVolatile
) && ((Variable
->Attributes
& EFI_VARIABLE_HARDWARE_ERROR_RECORD
) != EFI_VARIABLE_HARDWARE_ERROR_RECORD
)) {
923 CommonVariableTotalSize
+= VariableSize
;
926 Variable
= NextVariable
;
930 // Reinstall all in delete transition variables.
932 Variable
= GetStartPointer (VariableStoreHeader
);
933 while (IsValidVariableHeader (Variable
)) {
934 NextVariable
= GetNextVariablePtr (Variable
);
935 if (Variable
!= UpdatingVariable
&& Variable
!= UpdatingInDeletedTransition
&& Variable
->State
== (VAR_IN_DELETED_TRANSITION
& VAR_ADDED
)) {
938 // Buffer has cached all ADDED variable.
939 // Per IN_DELETED variable, we have to guarantee that
940 // no ADDED one in previous buffer.
944 AddedVariable
= GetStartPointer ((VARIABLE_STORE_HEADER
*) ValidBuffer
);
945 while (IsValidVariableHeader (AddedVariable
)) {
946 NextAddedVariable
= GetNextVariablePtr (AddedVariable
);
947 NameSize
= NameSizeOfVariable (AddedVariable
);
948 if (CompareGuid (&AddedVariable
->VendorGuid
, &Variable
->VendorGuid
) &&
949 NameSize
== NameSizeOfVariable (Variable
)
951 Point0
= (VOID
*) GetVariableNamePtr (AddedVariable
);
952 Point1
= (VOID
*) GetVariableNamePtr (Variable
);
953 if (CompareMem (Point0
, Point1
, NameSize
) == 0) {
958 AddedVariable
= NextAddedVariable
;
962 // Promote VAR_IN_DELETED_TRANSITION to VAR_ADDED.
964 VariableSize
= (UINTN
) NextVariable
- (UINTN
) Variable
;
965 CopyMem (CurrPtr
, (UINT8
*) Variable
, VariableSize
);
966 ((VARIABLE_HEADER
*) CurrPtr
)->State
= VAR_ADDED
;
967 CurrPtr
+= VariableSize
;
968 if ((!IsVolatile
) && ((Variable
->Attributes
& EFI_VARIABLE_HARDWARE_ERROR_RECORD
) == EFI_VARIABLE_HARDWARE_ERROR_RECORD
)) {
969 HwErrVariableTotalSize
+= VariableSize
;
970 } else if ((!IsVolatile
) && ((Variable
->Attributes
& EFI_VARIABLE_HARDWARE_ERROR_RECORD
) != EFI_VARIABLE_HARDWARE_ERROR_RECORD
)) {
971 CommonVariableTotalSize
+= VariableSize
;
976 Variable
= NextVariable
;
980 // Install the new variable if it is not NULL.
982 if (NewVariable
!= NULL
) {
983 if ((UINTN
) (CurrPtr
- ValidBuffer
) + NewVariableSize
> VariableStoreHeader
->Size
) {
985 // No enough space to store the new variable.
987 Status
= EFI_OUT_OF_RESOURCES
;
991 if ((NewVariable
->Attributes
& EFI_VARIABLE_HARDWARE_ERROR_RECORD
) == EFI_VARIABLE_HARDWARE_ERROR_RECORD
) {
992 HwErrVariableTotalSize
+= NewVariableSize
;
993 } else if ((NewVariable
->Attributes
& EFI_VARIABLE_HARDWARE_ERROR_RECORD
) != EFI_VARIABLE_HARDWARE_ERROR_RECORD
) {
994 CommonVariableTotalSize
+= NewVariableSize
;
996 if ((HwErrVariableTotalSize
> PcdGet32 (PcdHwErrStorageSize
)) ||
997 (CommonVariableTotalSize
> VariableStoreHeader
->Size
- sizeof (VARIABLE_STORE_HEADER
) - PcdGet32 (PcdHwErrStorageSize
))) {
999 // No enough space to store the new variable by NV or NV+HR attribute.
1001 Status
= EFI_OUT_OF_RESOURCES
;
1006 CopyMem (CurrPtr
, (UINT8
*) NewVariable
, NewVariableSize
);
1007 ((VARIABLE_HEADER
*) CurrPtr
)->State
= VAR_ADDED
;
1008 if (UpdatingVariable
!= NULL
) {
1009 UpdatingPtrTrack
->CurrPtr
= (VARIABLE_HEADER
*)((UINTN
)UpdatingPtrTrack
->StartPtr
+ ((UINTN
)CurrPtr
- (UINTN
)GetStartPointer ((VARIABLE_STORE_HEADER
*) ValidBuffer
)));
1010 UpdatingPtrTrack
->InDeletedTransitionPtr
= NULL
;
1012 CurrPtr
+= NewVariableSize
;
1018 // If volatile variable store, just copy valid buffer.
1020 SetMem ((UINT8
*) (UINTN
) VariableBase
, VariableStoreHeader
->Size
, 0xff);
1021 CopyMem ((UINT8
*) (UINTN
) VariableBase
, ValidBuffer
, (UINTN
) (CurrPtr
- ValidBuffer
));
1022 *LastVariableOffset
= (UINTN
) (CurrPtr
- ValidBuffer
);
1023 Status
= EFI_SUCCESS
;
1026 // If non-volatile variable store, perform FTW here.
1028 Status
= FtwVariableSpace (
1030 (VARIABLE_STORE_HEADER
*) ValidBuffer
1032 if (!EFI_ERROR (Status
)) {
1033 *LastVariableOffset
= (UINTN
) (CurrPtr
- ValidBuffer
);
1034 mVariableModuleGlobal
->HwErrVariableTotalSize
= HwErrVariableTotalSize
;
1035 mVariableModuleGlobal
->CommonVariableTotalSize
= CommonVariableTotalSize
;
1037 NextVariable
= GetStartPointer ((VARIABLE_STORE_HEADER
*)(UINTN
)VariableBase
);
1038 while (IsValidVariableHeader (NextVariable
)) {
1039 VariableSize
= NextVariable
->NameSize
+ NextVariable
->DataSize
+ sizeof (VARIABLE_HEADER
);
1040 if ((Variable
->Attributes
& EFI_VARIABLE_HARDWARE_ERROR_RECORD
) == EFI_VARIABLE_HARDWARE_ERROR_RECORD
) {
1041 mVariableModuleGlobal
->HwErrVariableTotalSize
+= HEADER_ALIGN (VariableSize
);
1042 } else if ((Variable
->Attributes
& EFI_VARIABLE_HARDWARE_ERROR_RECORD
) != EFI_VARIABLE_HARDWARE_ERROR_RECORD
) {
1043 mVariableModuleGlobal
->CommonVariableTotalSize
+= HEADER_ALIGN (VariableSize
);
1046 NextVariable
= GetNextVariablePtr (NextVariable
);
1048 *LastVariableOffset
= (UINTN
) NextVariable
- (UINTN
) VariableBase
;
1054 FreePool (ValidBuffer
);
1057 // For NV variable reclaim, we use mNvVariableCache as the buffer, so copy the data back.
1059 CopyMem (mNvVariableCache
, (UINT8
*)(UINTN
)VariableBase
, VariableStoreHeader
->Size
);
1061 if (NewPubKeyStore
!= NULL
) {
1062 FreePool (NewPubKeyStore
);
1065 if (NewPubKeyIndex
!= NULL
) {
1066 FreePool (NewPubKeyIndex
);
1074 Find the variable in the specified variable store.
1076 @param[in] VariableName Name of the variable to be found
1077 @param[in] VendorGuid Vendor GUID to be found.
1078 @param[in] IgnoreRtCheck Ignore EFI_VARIABLE_RUNTIME_ACCESS attribute
1079 check at runtime when searching variable.
1080 @param[in, out] PtrTrack Variable Track Pointer structure that contains Variable Information.
1082 @retval EFI_SUCCESS Variable found successfully
1083 @retval EFI_NOT_FOUND Variable not found
1087 IN CHAR16
*VariableName
,
1088 IN EFI_GUID
*VendorGuid
,
1089 IN BOOLEAN IgnoreRtCheck
,
1090 IN OUT VARIABLE_POINTER_TRACK
*PtrTrack
1093 VARIABLE_HEADER
*InDeletedVariable
;
1096 PtrTrack
->InDeletedTransitionPtr
= NULL
;
1099 // Find the variable by walk through HOB, volatile and non-volatile variable store.
1101 InDeletedVariable
= NULL
;
1103 for ( PtrTrack
->CurrPtr
= PtrTrack
->StartPtr
1104 ; (PtrTrack
->CurrPtr
< PtrTrack
->EndPtr
) && IsValidVariableHeader (PtrTrack
->CurrPtr
)
1105 ; PtrTrack
->CurrPtr
= GetNextVariablePtr (PtrTrack
->CurrPtr
)
1107 if (PtrTrack
->CurrPtr
->State
== VAR_ADDED
||
1108 PtrTrack
->CurrPtr
->State
== (VAR_IN_DELETED_TRANSITION
& VAR_ADDED
)
1110 if (IgnoreRtCheck
|| !AtRuntime () || ((PtrTrack
->CurrPtr
->Attributes
& EFI_VARIABLE_RUNTIME_ACCESS
) != 0)) {
1111 if (VariableName
[0] == 0) {
1112 if (PtrTrack
->CurrPtr
->State
== (VAR_IN_DELETED_TRANSITION
& VAR_ADDED
)) {
1113 InDeletedVariable
= PtrTrack
->CurrPtr
;
1115 PtrTrack
->InDeletedTransitionPtr
= InDeletedVariable
;
1119 if (CompareGuid (VendorGuid
, &PtrTrack
->CurrPtr
->VendorGuid
)) {
1120 Point
= (VOID
*) GetVariableNamePtr (PtrTrack
->CurrPtr
);
1122 ASSERT (NameSizeOfVariable (PtrTrack
->CurrPtr
) != 0);
1123 if (CompareMem (VariableName
, Point
, NameSizeOfVariable (PtrTrack
->CurrPtr
)) == 0) {
1124 if (PtrTrack
->CurrPtr
->State
== (VAR_IN_DELETED_TRANSITION
& VAR_ADDED
)) {
1125 InDeletedVariable
= PtrTrack
->CurrPtr
;
1127 PtrTrack
->InDeletedTransitionPtr
= InDeletedVariable
;
1137 PtrTrack
->CurrPtr
= InDeletedVariable
;
1138 return (PtrTrack
->CurrPtr
== NULL
) ? EFI_NOT_FOUND
: EFI_SUCCESS
;
1143 Finds variable in storage blocks of volatile and non-volatile storage areas.
1145 This code finds variable in storage blocks of volatile and non-volatile storage areas.
1146 If VariableName is an empty string, then we just return the first
1147 qualified variable without comparing VariableName and VendorGuid.
1148 If IgnoreRtCheck is TRUE, then we ignore the EFI_VARIABLE_RUNTIME_ACCESS attribute check
1149 at runtime when searching existing variable, only VariableName and VendorGuid are compared.
1150 Otherwise, variables without EFI_VARIABLE_RUNTIME_ACCESS are not visible at runtime.
1152 @param[in] VariableName Name of the variable to be found.
1153 @param[in] VendorGuid Vendor GUID to be found.
1154 @param[out] PtrTrack VARIABLE_POINTER_TRACK structure for output,
1155 including the range searched and the target position.
1156 @param[in] Global Pointer to VARIABLE_GLOBAL structure, including
1157 base of volatile variable storage area, base of
1158 NV variable storage area, and a lock.
1159 @param[in] IgnoreRtCheck Ignore EFI_VARIABLE_RUNTIME_ACCESS attribute
1160 check at runtime when searching variable.
1162 @retval EFI_INVALID_PARAMETER If VariableName is not an empty string, while
1164 @retval EFI_SUCCESS Variable successfully found.
1165 @retval EFI_NOT_FOUND Variable not found
1170 IN CHAR16
*VariableName
,
1171 IN EFI_GUID
*VendorGuid
,
1172 OUT VARIABLE_POINTER_TRACK
*PtrTrack
,
1173 IN VARIABLE_GLOBAL
*Global
,
1174 IN BOOLEAN IgnoreRtCheck
1178 VARIABLE_STORE_HEADER
*VariableStoreHeader
[VariableStoreTypeMax
];
1179 VARIABLE_STORE_TYPE Type
;
1181 if (VariableName
[0] != 0 && VendorGuid
== NULL
) {
1182 return EFI_INVALID_PARAMETER
;
1186 // 0: Volatile, 1: HOB, 2: Non-Volatile.
1187 // The index and attributes mapping must be kept in this order as RuntimeServiceGetNextVariableName
1188 // make use of this mapping to implement search algorithm.
1190 VariableStoreHeader
[VariableStoreTypeVolatile
] = (VARIABLE_STORE_HEADER
*) (UINTN
) Global
->VolatileVariableBase
;
1191 VariableStoreHeader
[VariableStoreTypeHob
] = (VARIABLE_STORE_HEADER
*) (UINTN
) Global
->HobVariableBase
;
1192 VariableStoreHeader
[VariableStoreTypeNv
] = mNvVariableCache
;
1195 // Find the variable by walk through HOB, volatile and non-volatile variable store.
1197 for (Type
= (VARIABLE_STORE_TYPE
) 0; Type
< VariableStoreTypeMax
; Type
++) {
1198 if (VariableStoreHeader
[Type
] == NULL
) {
1202 PtrTrack
->StartPtr
= GetStartPointer (VariableStoreHeader
[Type
]);
1203 PtrTrack
->EndPtr
= GetEndPointer (VariableStoreHeader
[Type
]);
1204 PtrTrack
->Volatile
= (BOOLEAN
) (Type
== VariableStoreTypeVolatile
);
1206 Status
= FindVariableEx (VariableName
, VendorGuid
, IgnoreRtCheck
, PtrTrack
);
1207 if (!EFI_ERROR (Status
)) {
1211 return EFI_NOT_FOUND
;
1215 Get index from supported language codes according to language string.
1217 This code is used to get corresponding index in supported language codes. It can handle
1218 RFC4646 and ISO639 language tags.
1219 In ISO639 language tags, take 3-characters as a delimitation to find matched string and calculate the index.
1220 In RFC4646 language tags, take semicolon as a delimitation to find matched string and calculate the index.
1223 SupportedLang = "engfraengfra"
1225 Iso639Language = TRUE
1226 The return value is "0".
1228 SupportedLang = "en;fr;en-US;fr-FR"
1230 Iso639Language = FALSE
1231 The return value is "3".
1233 @param SupportedLang Platform supported language codes.
1234 @param Lang Configured language.
1235 @param Iso639Language A bool value to signify if the handler is operated on ISO639 or RFC4646.
1237 @retval The index of language in the language codes.
1241 GetIndexFromSupportedLangCodes(
1242 IN CHAR8
*SupportedLang
,
1244 IN BOOLEAN Iso639Language
1248 UINTN CompareLength
;
1249 UINTN LanguageLength
;
1251 if (Iso639Language
) {
1252 CompareLength
= ISO_639_2_ENTRY_SIZE
;
1253 for (Index
= 0; Index
< AsciiStrLen (SupportedLang
); Index
+= CompareLength
) {
1254 if (AsciiStrnCmp (Lang
, SupportedLang
+ Index
, CompareLength
) == 0) {
1256 // Successfully find the index of Lang string in SupportedLang string.
1258 Index
= Index
/ CompareLength
;
1266 // Compare RFC4646 language code
1269 for (LanguageLength
= 0; Lang
[LanguageLength
] != '\0'; LanguageLength
++);
1271 for (Index
= 0; *SupportedLang
!= '\0'; Index
++, SupportedLang
+= CompareLength
) {
1273 // Skip ';' characters in SupportedLang
1275 for (; *SupportedLang
!= '\0' && *SupportedLang
== ';'; SupportedLang
++);
1277 // Determine the length of the next language code in SupportedLang
1279 for (CompareLength
= 0; SupportedLang
[CompareLength
] != '\0' && SupportedLang
[CompareLength
] != ';'; CompareLength
++);
1281 if ((CompareLength
== LanguageLength
) &&
1282 (AsciiStrnCmp (Lang
, SupportedLang
, CompareLength
) == 0)) {
1284 // Successfully find the index of Lang string in SupportedLang string.
1295 Get language string from supported language codes according to index.
1297 This code is used to get corresponding language strings in supported language codes. It can handle
1298 RFC4646 and ISO639 language tags.
1299 In ISO639 language tags, take 3-characters as a delimitation. Find language string according to the index.
1300 In RFC4646 language tags, take semicolon as a delimitation. Find language string according to the index.
1303 SupportedLang = "engfraengfra"
1305 Iso639Language = TRUE
1306 The return value is "fra".
1308 SupportedLang = "en;fr;en-US;fr-FR"
1310 Iso639Language = FALSE
1311 The return value is "fr".
1313 @param SupportedLang Platform supported language codes.
1314 @param Index The index in supported language codes.
1315 @param Iso639Language A bool value to signify if the handler is operated on ISO639 or RFC4646.
1317 @retval The language string in the language codes.
1321 GetLangFromSupportedLangCodes (
1322 IN CHAR8
*SupportedLang
,
1324 IN BOOLEAN Iso639Language
1328 UINTN CompareLength
;
1332 Supported
= SupportedLang
;
1333 if (Iso639Language
) {
1335 // According to the index of Lang string in SupportedLang string to get the language.
1336 // This code will be invoked in RUNTIME, therefore there is not a memory allocate/free operation.
1337 // In driver entry, it pre-allocates a runtime attribute memory to accommodate this string.
1339 CompareLength
= ISO_639_2_ENTRY_SIZE
;
1340 mVariableModuleGlobal
->Lang
[CompareLength
] = '\0';
1341 return CopyMem (mVariableModuleGlobal
->Lang
, SupportedLang
+ Index
* CompareLength
, CompareLength
);
1346 // Take semicolon as delimitation, sequentially traverse supported language codes.
1348 for (CompareLength
= 0; *Supported
!= ';' && *Supported
!= '\0'; CompareLength
++) {
1351 if ((*Supported
== '\0') && (SubIndex
!= Index
)) {
1353 // Have completed the traverse, but not find corrsponding string.
1354 // This case is not allowed to happen.
1359 if (SubIndex
== Index
) {
1361 // According to the index of Lang string in SupportedLang string to get the language.
1362 // As this code will be invoked in RUNTIME, therefore there is not memory allocate/free operation.
1363 // In driver entry, it pre-allocates a runtime attribute memory to accommodate this string.
1365 mVariableModuleGlobal
->PlatformLang
[CompareLength
] = '\0';
1366 return CopyMem (mVariableModuleGlobal
->PlatformLang
, Supported
- CompareLength
, CompareLength
);
1371 // Skip ';' characters in Supported
1373 for (; *Supported
!= '\0' && *Supported
== ';'; Supported
++);
1379 Returns a pointer to an allocated buffer that contains the best matching language
1380 from a set of supported languages.
1382 This function supports both ISO 639-2 and RFC 4646 language codes, but language
1383 code types may not be mixed in a single call to this function. This function
1384 supports a variable argument list that allows the caller to pass in a prioritized
1385 list of language codes to test against all the language codes in SupportedLanguages.
1387 If SupportedLanguages is NULL, then ASSERT().
1389 @param[in] SupportedLanguages A pointer to a Null-terminated ASCII string that
1390 contains a set of language codes in the format
1391 specified by Iso639Language.
1392 @param[in] Iso639Language If TRUE, then all language codes are assumed to be
1393 in ISO 639-2 format. If FALSE, then all language
1394 codes are assumed to be in RFC 4646 language format
1395 @param[in] ... A variable argument list that contains pointers to
1396 Null-terminated ASCII strings that contain one or more
1397 language codes in the format specified by Iso639Language.
1398 The first language code from each of these language
1399 code lists is used to determine if it is an exact or
1400 close match to any of the language codes in
1401 SupportedLanguages. Close matches only apply to RFC 4646
1402 language codes, and the matching algorithm from RFC 4647
1403 is used to determine if a close match is present. If
1404 an exact or close match is found, then the matching
1405 language code from SupportedLanguages is returned. If
1406 no matches are found, then the next variable argument
1407 parameter is evaluated. The variable argument list
1408 is terminated by a NULL.
1410 @retval NULL The best matching language could not be found in SupportedLanguages.
1411 @retval NULL There are not enough resources available to return the best matching
1413 @retval Other A pointer to a Null-terminated ASCII string that is the best matching
1414 language in SupportedLanguages.
1419 VariableGetBestLanguage (
1420 IN CONST CHAR8
*SupportedLanguages
,
1421 IN BOOLEAN Iso639Language
,
1427 UINTN CompareLength
;
1428 UINTN LanguageLength
;
1429 CONST CHAR8
*Supported
;
1432 if (SupportedLanguages
== NULL
) {
1436 VA_START (Args
, Iso639Language
);
1437 while ((Language
= VA_ARG (Args
, CHAR8
*)) != NULL
) {
1439 // Default to ISO 639-2 mode
1442 LanguageLength
= MIN (3, AsciiStrLen (Language
));
1445 // If in RFC 4646 mode, then determine the length of the first RFC 4646 language code in Language
1447 if (!Iso639Language
) {
1448 for (LanguageLength
= 0; Language
[LanguageLength
] != 0 && Language
[LanguageLength
] != ';'; LanguageLength
++);
1452 // Trim back the length of Language used until it is empty
1454 while (LanguageLength
> 0) {
1456 // Loop through all language codes in SupportedLanguages
1458 for (Supported
= SupportedLanguages
; *Supported
!= '\0'; Supported
+= CompareLength
) {
1460 // In RFC 4646 mode, then Loop through all language codes in SupportedLanguages
1462 if (!Iso639Language
) {
1464 // Skip ';' characters in Supported
1466 for (; *Supported
!= '\0' && *Supported
== ';'; Supported
++);
1468 // Determine the length of the next language code in Supported
1470 for (CompareLength
= 0; Supported
[CompareLength
] != 0 && Supported
[CompareLength
] != ';'; CompareLength
++);
1472 // If Language is longer than the Supported, then skip to the next language
1474 if (LanguageLength
> CompareLength
) {
1479 // See if the first LanguageLength characters in Supported match Language
1481 if (AsciiStrnCmp (Supported
, Language
, LanguageLength
) == 0) {
1484 Buffer
= Iso639Language
? mVariableModuleGlobal
->Lang
: mVariableModuleGlobal
->PlatformLang
;
1485 Buffer
[CompareLength
] = '\0';
1486 return CopyMem (Buffer
, Supported
, CompareLength
);
1490 if (Iso639Language
) {
1492 // If ISO 639 mode, then each language can only be tested once
1497 // If RFC 4646 mode, then trim Language from the right to the next '-' character
1499 for (LanguageLength
--; LanguageLength
> 0 && Language
[LanguageLength
] != '-'; LanguageLength
--);
1506 // No matches were found
1512 Hook the operations in PlatformLangCodes, LangCodes, PlatformLang and Lang.
1514 When setting Lang/LangCodes, simultaneously update PlatformLang/PlatformLangCodes.
1516 According to UEFI spec, PlatformLangCodes/LangCodes are only set once in firmware initialization,
1517 and are read-only. Therefore, in variable driver, only store the original value for other use.
1519 @param[in] VariableName Name of variable.
1521 @param[in] Data Variable data.
1523 @param[in] DataSize Size of data. 0 means delete.
1525 @retval EFI_SUCCESS The update operation is successful or ignored.
1526 @retval EFI_WRITE_PROTECTED Update PlatformLangCodes/LangCodes at runtime.
1527 @retval EFI_OUT_OF_RESOURCES No enough variable space to do the update operation.
1528 @retval Others Other errors happened during the update operation.
1532 AutoUpdateLangVariable (
1533 IN CHAR16
*VariableName
,
1539 CHAR8
*BestPlatformLang
;
1543 VARIABLE_POINTER_TRACK Variable
;
1544 BOOLEAN SetLanguageCodes
;
1547 // Don't do updates for delete operation
1549 if (DataSize
== 0) {
1553 SetLanguageCodes
= FALSE
;
1555 if (StrCmp (VariableName
, EFI_PLATFORM_LANG_CODES_VARIABLE_NAME
) == 0) {
1557 // PlatformLangCodes is a volatile variable, so it can not be updated at runtime.
1560 return EFI_WRITE_PROTECTED
;
1563 SetLanguageCodes
= TRUE
;
1566 // According to UEFI spec, PlatformLangCodes is only set once in firmware initialization, and is read-only
1567 // Therefore, in variable driver, only store the original value for other use.
1569 if (mVariableModuleGlobal
->PlatformLangCodes
!= NULL
) {
1570 FreePool (mVariableModuleGlobal
->PlatformLangCodes
);
1572 mVariableModuleGlobal
->PlatformLangCodes
= AllocateRuntimeCopyPool (DataSize
, Data
);
1573 ASSERT (mVariableModuleGlobal
->PlatformLangCodes
!= NULL
);
1576 // PlatformLang holds a single language from PlatformLangCodes,
1577 // so the size of PlatformLangCodes is enough for the PlatformLang.
1579 if (mVariableModuleGlobal
->PlatformLang
!= NULL
) {
1580 FreePool (mVariableModuleGlobal
->PlatformLang
);
1582 mVariableModuleGlobal
->PlatformLang
= AllocateRuntimePool (DataSize
);
1583 ASSERT (mVariableModuleGlobal
->PlatformLang
!= NULL
);
1585 } else if (StrCmp (VariableName
, EFI_LANG_CODES_VARIABLE_NAME
) == 0) {
1587 // LangCodes is a volatile variable, so it can not be updated at runtime.
1590 return EFI_WRITE_PROTECTED
;
1593 SetLanguageCodes
= TRUE
;
1596 // According to UEFI spec, LangCodes is only set once in firmware initialization, and is read-only
1597 // Therefore, in variable driver, only store the original value for other use.
1599 if (mVariableModuleGlobal
->LangCodes
!= NULL
) {
1600 FreePool (mVariableModuleGlobal
->LangCodes
);
1602 mVariableModuleGlobal
->LangCodes
= AllocateRuntimeCopyPool (DataSize
, Data
);
1603 ASSERT (mVariableModuleGlobal
->LangCodes
!= NULL
);
1606 if (SetLanguageCodes
1607 && (mVariableModuleGlobal
->PlatformLangCodes
!= NULL
)
1608 && (mVariableModuleGlobal
->LangCodes
!= NULL
)) {
1610 // Update Lang if PlatformLang is already set
1611 // Update PlatformLang if Lang is already set
1613 Status
= FindVariable (EFI_PLATFORM_LANG_VARIABLE_NAME
, &gEfiGlobalVariableGuid
, &Variable
, &mVariableModuleGlobal
->VariableGlobal
, FALSE
);
1614 if (!EFI_ERROR (Status
)) {
1618 VariableName
= EFI_PLATFORM_LANG_VARIABLE_NAME
;
1619 Data
= GetVariableDataPtr (Variable
.CurrPtr
);
1620 DataSize
= Variable
.CurrPtr
->DataSize
;
1622 Status
= FindVariable (EFI_LANG_VARIABLE_NAME
, &gEfiGlobalVariableGuid
, &Variable
, &mVariableModuleGlobal
->VariableGlobal
, FALSE
);
1623 if (!EFI_ERROR (Status
)) {
1625 // Update PlatformLang
1627 VariableName
= EFI_LANG_VARIABLE_NAME
;
1628 Data
= GetVariableDataPtr (Variable
.CurrPtr
);
1629 DataSize
= Variable
.CurrPtr
->DataSize
;
1632 // Neither PlatformLang nor Lang is set, directly return
1639 Status
= EFI_SUCCESS
;
1642 // According to UEFI spec, "Lang" and "PlatformLang" is NV|BS|RT attributions.
1644 Attributes
= EFI_VARIABLE_NON_VOLATILE
| EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_RUNTIME_ACCESS
;
1646 if (StrCmp (VariableName
, EFI_PLATFORM_LANG_VARIABLE_NAME
) == 0) {
1648 // Update Lang when PlatformLangCodes/LangCodes were set.
1650 if ((mVariableModuleGlobal
->PlatformLangCodes
!= NULL
) && (mVariableModuleGlobal
->LangCodes
!= NULL
)) {
1652 // When setting PlatformLang, firstly get most matched language string from supported language codes.
1654 BestPlatformLang
= VariableGetBestLanguage (mVariableModuleGlobal
->PlatformLangCodes
, FALSE
, Data
, NULL
);
1655 if (BestPlatformLang
!= NULL
) {
1657 // Get the corresponding index in language codes.
1659 Index
= GetIndexFromSupportedLangCodes (mVariableModuleGlobal
->PlatformLangCodes
, BestPlatformLang
, FALSE
);
1662 // Get the corresponding ISO639 language tag according to RFC4646 language tag.
1664 BestLang
= GetLangFromSupportedLangCodes (mVariableModuleGlobal
->LangCodes
, Index
, TRUE
);
1667 // Successfully convert PlatformLang to Lang, and set the BestLang value into Lang variable simultaneously.
1669 FindVariable (EFI_LANG_VARIABLE_NAME
, &gEfiGlobalVariableGuid
, &Variable
, &mVariableModuleGlobal
->VariableGlobal
, FALSE
);
1671 Status
= UpdateVariable (EFI_LANG_VARIABLE_NAME
, &gEfiGlobalVariableGuid
, BestLang
,
1672 ISO_639_2_ENTRY_SIZE
+ 1, Attributes
, 0, 0, &Variable
, NULL
);
1674 DEBUG ((EFI_D_INFO
, "Variable Driver Auto Update PlatformLang, PlatformLang:%a, Lang:%a Status: %r\n", BestPlatformLang
, BestLang
, Status
));
1678 } else if (StrCmp (VariableName
, EFI_LANG_VARIABLE_NAME
) == 0) {
1680 // Update PlatformLang when PlatformLangCodes/LangCodes were set.
1682 if ((mVariableModuleGlobal
->PlatformLangCodes
!= NULL
) && (mVariableModuleGlobal
->LangCodes
!= NULL
)) {
1684 // When setting Lang, firstly get most matched language string from supported language codes.
1686 BestLang
= VariableGetBestLanguage (mVariableModuleGlobal
->LangCodes
, TRUE
, Data
, NULL
);
1687 if (BestLang
!= NULL
) {
1689 // Get the corresponding index in language codes.
1691 Index
= GetIndexFromSupportedLangCodes (mVariableModuleGlobal
->LangCodes
, BestLang
, TRUE
);
1694 // Get the corresponding RFC4646 language tag according to ISO639 language tag.
1696 BestPlatformLang
= GetLangFromSupportedLangCodes (mVariableModuleGlobal
->PlatformLangCodes
, Index
, FALSE
);
1699 // Successfully convert Lang to PlatformLang, and set the BestPlatformLang value into PlatformLang variable simultaneously.
1701 FindVariable (EFI_PLATFORM_LANG_VARIABLE_NAME
, &gEfiGlobalVariableGuid
, &Variable
, &mVariableModuleGlobal
->VariableGlobal
, FALSE
);
1703 Status
= UpdateVariable (EFI_PLATFORM_LANG_VARIABLE_NAME
, &gEfiGlobalVariableGuid
, BestPlatformLang
,
1704 AsciiStrSize (BestPlatformLang
), Attributes
, 0, 0, &Variable
, NULL
);
1706 DEBUG ((EFI_D_INFO
, "Variable Driver Auto Update Lang, Lang:%a, PlatformLang:%a Status: %r\n", BestLang
, BestPlatformLang
, Status
));
1715 Update the variable region with Variable information. If EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS is set,
1716 index of associated public key is needed.
1718 @param[in] VariableName Name of variable.
1719 @param[in] VendorGuid Guid of variable.
1720 @param[in] Data Variable data.
1721 @param[in] DataSize Size of data. 0 means delete.
1722 @param[in] Attributes Attributes of the variable.
1723 @param[in] KeyIndex Index of associated public key.
1724 @param[in] MonotonicCount Value of associated monotonic count.
1725 @param[in, out] CacheVariable The variable information which is used to keep track of variable usage.
1726 @param[in] TimeStamp Value of associated TimeStamp.
1728 @retval EFI_SUCCESS The update operation is success.
1729 @retval EFI_OUT_OF_RESOURCES Variable region is full, can not write other data into this region.
1734 IN CHAR16
*VariableName
,
1735 IN EFI_GUID
*VendorGuid
,
1738 IN UINT32 Attributes OPTIONAL
,
1739 IN UINT32 KeyIndex OPTIONAL
,
1740 IN UINT64 MonotonicCount OPTIONAL
,
1741 IN OUT VARIABLE_POINTER_TRACK
*CacheVariable
,
1742 IN EFI_TIME
*TimeStamp OPTIONAL
1746 VARIABLE_HEADER
*NextVariable
;
1749 UINTN NonVolatileVarableStoreSize
;
1750 UINTN VarNameOffset
;
1751 UINTN VarDataOffset
;
1755 EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*Fvb
;
1757 VARIABLE_POINTER_TRACK
*Variable
;
1758 VARIABLE_POINTER_TRACK NvVariable
;
1759 VARIABLE_STORE_HEADER
*VariableStoreHeader
;
1761 UINT8
*BufferForMerge
;
1762 UINTN MergedBufSize
;
1766 if (mVariableModuleGlobal
->FvbInstance
== NULL
) {
1768 // The FVB protocol is not installed, so the EFI_VARIABLE_WRITE_ARCH_PROTOCOL is not installed.
1770 if ((Attributes
& EFI_VARIABLE_NON_VOLATILE
) != 0) {
1772 // Trying to update NV variable prior to the installation of EFI_VARIABLE_WRITE_ARCH_PROTOCOL
1774 return EFI_NOT_AVAILABLE_YET
;
1775 } else if ((Attributes
& EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS
) != 0) {
1777 // Trying to update volatile authenticated variable prior to the installation of EFI_VARIABLE_WRITE_ARCH_PROTOCOL
1778 // The authenticated variable perhaps is not initialized, just return here.
1780 return EFI_NOT_AVAILABLE_YET
;
1784 if ((CacheVariable
->CurrPtr
== NULL
) || CacheVariable
->Volatile
) {
1785 Variable
= CacheVariable
;
1788 // Update/Delete existing NV variable.
1789 // CacheVariable points to the variable in the memory copy of Flash area
1790 // Now let Variable points to the same variable in Flash area.
1792 VariableStoreHeader
= (VARIABLE_STORE_HEADER
*) ((UINTN
) mVariableModuleGlobal
->VariableGlobal
.NonVolatileVariableBase
);
1793 Variable
= &NvVariable
;
1794 Variable
->StartPtr
= GetStartPointer (VariableStoreHeader
);
1795 Variable
->EndPtr
= GetEndPointer (VariableStoreHeader
);
1796 Variable
->CurrPtr
= (VARIABLE_HEADER
*)((UINTN
)Variable
->StartPtr
+ ((UINTN
)CacheVariable
->CurrPtr
- (UINTN
)CacheVariable
->StartPtr
));
1797 if (CacheVariable
->InDeletedTransitionPtr
!= NULL
) {
1798 Variable
->InDeletedTransitionPtr
= (VARIABLE_HEADER
*)((UINTN
)Variable
->StartPtr
+ ((UINTN
)CacheVariable
->InDeletedTransitionPtr
- (UINTN
)CacheVariable
->StartPtr
));
1800 Variable
->InDeletedTransitionPtr
= NULL
;
1802 Variable
->Volatile
= FALSE
;
1805 Fvb
= mVariableModuleGlobal
->FvbInstance
;
1808 // Tricky part: Use scratch data area at the end of volatile variable store
1809 // as a temporary storage.
1811 NextVariable
= GetEndPointer ((VARIABLE_STORE_HEADER
*) ((UINTN
) mVariableModuleGlobal
->VariableGlobal
.VolatileVariableBase
));
1812 ScratchSize
= MAX (PcdGet32 (PcdMaxVariableSize
), PcdGet32 (PcdMaxHardwareErrorVariableSize
));
1813 SetMem (NextVariable
, ScratchSize
, 0xff);
1816 if (Variable
->CurrPtr
!= NULL
) {
1818 // Update/Delete existing variable.
1822 // If AtRuntime and the variable is Volatile and Runtime Access,
1823 // the volatile is ReadOnly, and SetVariable should be aborted and
1824 // return EFI_WRITE_PROTECTED.
1826 if (Variable
->Volatile
) {
1827 Status
= EFI_WRITE_PROTECTED
;
1831 // Only variable that have NV attributes can be updated/deleted in Runtime.
1833 if ((Variable
->CurrPtr
->Attributes
& EFI_VARIABLE_NON_VOLATILE
) == 0) {
1834 Status
= EFI_INVALID_PARAMETER
;
1839 // Only variable that have RT attributes can be updated/deleted in Runtime.
1841 if ((Variable
->CurrPtr
->Attributes
& EFI_VARIABLE_RUNTIME_ACCESS
) == 0) {
1842 Status
= EFI_INVALID_PARAMETER
;
1848 // Setting a data variable with no access, or zero DataSize attributes
1849 // causes it to be deleted.
1850 // When the EFI_VARIABLE_APPEND_WRITE attribute is set, DataSize of zero will
1851 // not delete the variable.
1853 if ((((Attributes
& EFI_VARIABLE_APPEND_WRITE
) == 0) && (DataSize
== 0))|| ((Attributes
& (EFI_VARIABLE_RUNTIME_ACCESS
| EFI_VARIABLE_BOOTSERVICE_ACCESS
)) == 0)) {
1854 if (Variable
->InDeletedTransitionPtr
!= NULL
) {
1856 // Both ADDED and IN_DELETED_TRANSITION variable are present,
1857 // set IN_DELETED_TRANSITION one to DELETED state first.
1859 State
= Variable
->InDeletedTransitionPtr
->State
;
1860 State
&= VAR_DELETED
;
1861 Status
= UpdateVariableStore (
1862 &mVariableModuleGlobal
->VariableGlobal
,
1866 (UINTN
) &Variable
->InDeletedTransitionPtr
->State
,
1870 if (!EFI_ERROR (Status
)) {
1871 if (!Variable
->Volatile
) {
1872 ASSERT (CacheVariable
->InDeletedTransitionPtr
!= NULL
);
1873 CacheVariable
->InDeletedTransitionPtr
->State
= State
;
1880 State
= Variable
->CurrPtr
->State
;
1881 State
&= VAR_DELETED
;
1883 Status
= UpdateVariableStore (
1884 &mVariableModuleGlobal
->VariableGlobal
,
1888 (UINTN
) &Variable
->CurrPtr
->State
,
1892 if (!EFI_ERROR (Status
)) {
1893 UpdateVariableInfo (VariableName
, VendorGuid
, Variable
->Volatile
, FALSE
, FALSE
, TRUE
, FALSE
);
1894 if (!Variable
->Volatile
) {
1895 CacheVariable
->CurrPtr
->State
= State
;
1896 FlushHobVariableToFlash (VariableName
, VendorGuid
);
1902 // If the variable is marked valid, and the same data has been passed in,
1903 // then return to the caller immediately.
1905 if (DataSizeOfVariable (Variable
->CurrPtr
) == DataSize
&&
1906 (CompareMem (Data
, GetVariableDataPtr (Variable
->CurrPtr
), DataSize
) == 0) &&
1907 ((Attributes
& EFI_VARIABLE_APPEND_WRITE
) == 0) &&
1908 (TimeStamp
== NULL
)) {
1910 // Variable content unchanged and no need to update timestamp, just return.
1912 UpdateVariableInfo (VariableName
, VendorGuid
, Variable
->Volatile
, FALSE
, TRUE
, FALSE
, FALSE
);
1913 Status
= EFI_SUCCESS
;
1915 } else if ((Variable
->CurrPtr
->State
== VAR_ADDED
) ||
1916 (Variable
->CurrPtr
->State
== (VAR_ADDED
& VAR_IN_DELETED_TRANSITION
))) {
1919 // EFI_VARIABLE_APPEND_WRITE attribute only effects for existing variable
1921 if ((Attributes
& EFI_VARIABLE_APPEND_WRITE
) != 0) {
1923 // NOTE: From 0 to DataOffset of NextVariable is reserved for Variable Header and Name.
1924 // From DataOffset of NextVariable is to save the existing variable data.
1926 DataOffset
= sizeof (VARIABLE_HEADER
) + Variable
->CurrPtr
->NameSize
+ GET_PAD_SIZE (Variable
->CurrPtr
->NameSize
);
1927 BufferForMerge
= (UINT8
*) ((UINTN
) NextVariable
+ DataOffset
);
1928 CopyMem (BufferForMerge
, (UINT8
*) ((UINTN
) Variable
->CurrPtr
+ DataOffset
), Variable
->CurrPtr
->DataSize
);
1931 // Set Max Common Variable Data Size as default MaxDataSize
1933 MaxDataSize
= PcdGet32 (PcdMaxVariableSize
) - DataOffset
;
1935 if ((CompareGuid (VendorGuid
, &gEfiImageSecurityDatabaseGuid
) &&
1936 ((StrCmp (VariableName
, EFI_IMAGE_SECURITY_DATABASE
) == 0) || (StrCmp (VariableName
, EFI_IMAGE_SECURITY_DATABASE1
) == 0))) ||
1937 (CompareGuid (VendorGuid
, &gEfiGlobalVariableGuid
) && (StrCmp (VariableName
, EFI_KEY_EXCHANGE_KEY_NAME
) == 0))) {
1939 // For variables with formatted as EFI_SIGNATURE_LIST, the driver shall not perform an append of
1940 // EFI_SIGNATURE_DATA values that are already part of the existing variable value.
1942 Status
= AppendSignatureList (
1944 Variable
->CurrPtr
->DataSize
,
1945 MaxDataSize
- Variable
->CurrPtr
->DataSize
,
1950 if (Status
== EFI_BUFFER_TOO_SMALL
) {
1952 // Signature List is too long, Failed to Append.
1954 Status
= EFI_INVALID_PARAMETER
;
1958 if (MergedBufSize
== Variable
->CurrPtr
->DataSize
) {
1959 if ((TimeStamp
== NULL
) || CompareTimeStamp (TimeStamp
, &Variable
->CurrPtr
->TimeStamp
)) {
1961 // New EFI_SIGNATURE_DATA is not found and timestamp is not later
1962 // than current timestamp, return EFI_SUCCESS directly.
1964 UpdateVariableInfo (VariableName
, VendorGuid
, Variable
->Volatile
, FALSE
, TRUE
, FALSE
, FALSE
);
1965 Status
= EFI_SUCCESS
;
1971 // For other Variables, append the new data to the end of existing data.
1972 // Max Harware error record variable data size is different from common variable
1974 if ((Attributes
& EFI_VARIABLE_HARDWARE_ERROR_RECORD
) == EFI_VARIABLE_HARDWARE_ERROR_RECORD
) {
1975 MaxDataSize
= PcdGet32 (PcdMaxHardwareErrorVariableSize
) - DataOffset
;
1978 if (Variable
->CurrPtr
->DataSize
+ DataSize
> MaxDataSize
) {
1980 // Existing data size + new data size exceed maximum variable size limitation.
1982 Status
= EFI_INVALID_PARAMETER
;
1985 CopyMem ((UINT8
*) ((UINTN
) BufferForMerge
+ Variable
->CurrPtr
->DataSize
), Data
, DataSize
);
1986 MergedBufSize
= Variable
->CurrPtr
->DataSize
+ DataSize
;
1990 // BufferForMerge(from DataOffset of NextVariable) has included the merged existing and new data.
1992 Data
= BufferForMerge
;
1993 DataSize
= MergedBufSize
;
1998 // Mark the old variable as in delete transition.
2000 State
= Variable
->CurrPtr
->State
;
2001 State
&= VAR_IN_DELETED_TRANSITION
;
2003 Status
= UpdateVariableStore (
2004 &mVariableModuleGlobal
->VariableGlobal
,
2008 (UINTN
) &Variable
->CurrPtr
->State
,
2012 if (EFI_ERROR (Status
)) {
2015 if (!Variable
->Volatile
) {
2016 CacheVariable
->CurrPtr
->State
= State
;
2021 // Not found existing variable. Create a new variable.
2024 if ((DataSize
== 0) && ((Attributes
& EFI_VARIABLE_APPEND_WRITE
) != 0)) {
2025 Status
= EFI_SUCCESS
;
2030 // Make sure we are trying to create a new variable.
2031 // Setting a data variable with zero DataSize or no access attributes means to delete it.
2033 if (DataSize
== 0 || (Attributes
& (EFI_VARIABLE_RUNTIME_ACCESS
| EFI_VARIABLE_BOOTSERVICE_ACCESS
)) == 0) {
2034 Status
= EFI_NOT_FOUND
;
2039 // Only variable have NV|RT attribute can be created in Runtime.
2042 (((Attributes
& EFI_VARIABLE_RUNTIME_ACCESS
) == 0) || ((Attributes
& EFI_VARIABLE_NON_VOLATILE
) == 0))) {
2043 Status
= EFI_INVALID_PARAMETER
;
2049 // Function part - create a new variable and copy the data.
2050 // Both update a variable and create a variable will come here.
2052 NextVariable
->StartId
= VARIABLE_DATA
;
2054 // NextVariable->State = VAR_ADDED;
2056 NextVariable
->Reserved
= 0;
2057 NextVariable
->PubKeyIndex
= KeyIndex
;
2058 NextVariable
->MonotonicCount
= MonotonicCount
;
2059 ZeroMem (&NextVariable
->TimeStamp
, sizeof (EFI_TIME
));
2061 if (((Attributes
& EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS
) != 0) &&
2062 (TimeStamp
!= NULL
)) {
2063 if ((Attributes
& EFI_VARIABLE_APPEND_WRITE
) == 0) {
2064 CopyMem (&NextVariable
->TimeStamp
, TimeStamp
, sizeof (EFI_TIME
));
2067 // In the case when the EFI_VARIABLE_APPEND_WRITE attribute is set, only
2068 // when the new TimeStamp value is later than the current timestamp associated
2069 // with the variable, we need associate the new timestamp with the updated value.
2071 if (Variable
->CurrPtr
!= NULL
) {
2072 if (CompareTimeStamp (&Variable
->CurrPtr
->TimeStamp
, TimeStamp
)) {
2073 CopyMem (&NextVariable
->TimeStamp
, TimeStamp
, sizeof (EFI_TIME
));
2080 // The EFI_VARIABLE_APPEND_WRITE attribute will never be set in the returned
2081 // Attributes bitmask parameter of a GetVariable() call.
2083 NextVariable
->Attributes
= Attributes
& (~EFI_VARIABLE_APPEND_WRITE
);
2085 VarNameOffset
= sizeof (VARIABLE_HEADER
);
2086 VarNameSize
= StrSize (VariableName
);
2088 (UINT8
*) ((UINTN
) NextVariable
+ VarNameOffset
),
2092 VarDataOffset
= VarNameOffset
+ VarNameSize
+ GET_PAD_SIZE (VarNameSize
);
2095 // If DataReady is TRUE, it means the variable data has been saved into
2096 // NextVariable during EFI_VARIABLE_APPEND_WRITE operation preparation.
2100 (UINT8
*) ((UINTN
) NextVariable
+ VarDataOffset
),
2106 CopyMem (&NextVariable
->VendorGuid
, VendorGuid
, sizeof (EFI_GUID
));
2108 // There will be pad bytes after Data, the NextVariable->NameSize and
2109 // NextVariable->DataSize should not include pad size so that variable
2110 // service can get actual size in GetVariable.
2112 NextVariable
->NameSize
= (UINT32
)VarNameSize
;
2113 NextVariable
->DataSize
= (UINT32
)DataSize
;
2116 // The actual size of the variable that stores in storage should
2117 // include pad size.
2119 VarSize
= VarDataOffset
+ DataSize
+ GET_PAD_SIZE (DataSize
);
2120 if ((Attributes
& EFI_VARIABLE_NON_VOLATILE
) != 0) {
2122 // Create a nonvolatile variable.
2125 NonVolatileVarableStoreSize
= ((VARIABLE_STORE_HEADER
*)(UINTN
)(mVariableModuleGlobal
->VariableGlobal
.NonVolatileVariableBase
))->Size
;
2126 if ((((Attributes
& EFI_VARIABLE_HARDWARE_ERROR_RECORD
) != 0)
2127 && ((VarSize
+ mVariableModuleGlobal
->HwErrVariableTotalSize
) > PcdGet32 (PcdHwErrStorageSize
)))
2128 || (((Attributes
& EFI_VARIABLE_HARDWARE_ERROR_RECORD
) == 0)
2129 && ((VarSize
+ mVariableModuleGlobal
->CommonVariableTotalSize
) > NonVolatileVarableStoreSize
- sizeof (VARIABLE_STORE_HEADER
) - PcdGet32 (PcdHwErrStorageSize
)))) {
2131 Status
= EFI_OUT_OF_RESOURCES
;
2135 // Perform garbage collection & reclaim operation, and integrate the new variable at the same time.
2138 mVariableModuleGlobal
->VariableGlobal
.NonVolatileVariableBase
,
2139 &mVariableModuleGlobal
->NonVolatileLastVariableOffset
,
2143 HEADER_ALIGN (VarSize
),
2146 if (!EFI_ERROR (Status
)) {
2148 // The new variable has been integrated successfully during reclaiming.
2150 if (Variable
->CurrPtr
!= NULL
) {
2151 CacheVariable
->CurrPtr
= (VARIABLE_HEADER
*)((UINTN
) CacheVariable
->StartPtr
+ ((UINTN
) Variable
->CurrPtr
- (UINTN
) Variable
->StartPtr
));
2152 CacheVariable
->InDeletedTransitionPtr
= NULL
;
2154 UpdateVariableInfo (VariableName
, VendorGuid
, FALSE
, FALSE
, TRUE
, FALSE
, FALSE
);
2155 FlushHobVariableToFlash (VariableName
, VendorGuid
);
2161 // 1. Write variable header
2162 // 2. Set variable state to header valid
2163 // 3. Write variable data
2164 // 4. Set variable state to valid
2169 CacheOffset
= mVariableModuleGlobal
->NonVolatileLastVariableOffset
;
2170 Status
= UpdateVariableStore (
2171 &mVariableModuleGlobal
->VariableGlobal
,
2175 mVariableModuleGlobal
->NonVolatileLastVariableOffset
,
2176 sizeof (VARIABLE_HEADER
),
2177 (UINT8
*) NextVariable
2180 if (EFI_ERROR (Status
)) {
2187 NextVariable
->State
= VAR_HEADER_VALID_ONLY
;
2188 Status
= UpdateVariableStore (
2189 &mVariableModuleGlobal
->VariableGlobal
,
2193 mVariableModuleGlobal
->NonVolatileLastVariableOffset
+ OFFSET_OF (VARIABLE_HEADER
, State
),
2195 &NextVariable
->State
2198 if (EFI_ERROR (Status
)) {
2204 Status
= UpdateVariableStore (
2205 &mVariableModuleGlobal
->VariableGlobal
,
2209 mVariableModuleGlobal
->NonVolatileLastVariableOffset
+ sizeof (VARIABLE_HEADER
),
2210 (UINT32
) VarSize
- sizeof (VARIABLE_HEADER
),
2211 (UINT8
*) NextVariable
+ sizeof (VARIABLE_HEADER
)
2214 if (EFI_ERROR (Status
)) {
2220 NextVariable
->State
= VAR_ADDED
;
2221 Status
= UpdateVariableStore (
2222 &mVariableModuleGlobal
->VariableGlobal
,
2226 mVariableModuleGlobal
->NonVolatileLastVariableOffset
+ OFFSET_OF (VARIABLE_HEADER
, State
),
2228 &NextVariable
->State
2231 if (EFI_ERROR (Status
)) {
2235 mVariableModuleGlobal
->NonVolatileLastVariableOffset
+= HEADER_ALIGN (VarSize
);
2237 if ((Attributes
& EFI_VARIABLE_HARDWARE_ERROR_RECORD
) != 0) {
2238 mVariableModuleGlobal
->HwErrVariableTotalSize
+= HEADER_ALIGN (VarSize
);
2240 mVariableModuleGlobal
->CommonVariableTotalSize
+= HEADER_ALIGN (VarSize
);
2243 // update the memory copy of Flash region.
2245 CopyMem ((UINT8
*)mNvVariableCache
+ CacheOffset
, (UINT8
*)NextVariable
, VarSize
);
2248 // Create a volatile variable.
2252 if ((UINT32
) (VarSize
+ mVariableModuleGlobal
->VolatileLastVariableOffset
) >
2253 ((VARIABLE_STORE_HEADER
*) ((UINTN
) (mVariableModuleGlobal
->VariableGlobal
.VolatileVariableBase
)))->Size
) {
2255 // Perform garbage collection & reclaim operation, and integrate the new variable at the same time.
2258 mVariableModuleGlobal
->VariableGlobal
.VolatileVariableBase
,
2259 &mVariableModuleGlobal
->VolatileLastVariableOffset
,
2263 HEADER_ALIGN (VarSize
),
2266 if (!EFI_ERROR (Status
)) {
2268 // The new variable has been integrated successfully during reclaiming.
2270 if (Variable
->CurrPtr
!= NULL
) {
2271 CacheVariable
->CurrPtr
= (VARIABLE_HEADER
*)((UINTN
) CacheVariable
->StartPtr
+ ((UINTN
) Variable
->CurrPtr
- (UINTN
) Variable
->StartPtr
));
2272 CacheVariable
->InDeletedTransitionPtr
= NULL
;
2274 UpdateVariableInfo (VariableName
, VendorGuid
, TRUE
, FALSE
, TRUE
, FALSE
, FALSE
);
2279 NextVariable
->State
= VAR_ADDED
;
2280 Status
= UpdateVariableStore (
2281 &mVariableModuleGlobal
->VariableGlobal
,
2285 mVariableModuleGlobal
->VolatileLastVariableOffset
,
2287 (UINT8
*) NextVariable
2290 if (EFI_ERROR (Status
)) {
2294 mVariableModuleGlobal
->VolatileLastVariableOffset
+= HEADER_ALIGN (VarSize
);
2298 // Mark the old variable as deleted.
2300 if (!EFI_ERROR (Status
) && Variable
->CurrPtr
!= NULL
) {
2301 if (Variable
->InDeletedTransitionPtr
!= NULL
) {
2303 // Both ADDED and IN_DELETED_TRANSITION old variable are present,
2304 // set IN_DELETED_TRANSITION one to DELETED state first.
2306 State
= Variable
->InDeletedTransitionPtr
->State
;
2307 State
&= VAR_DELETED
;
2308 Status
= UpdateVariableStore (
2309 &mVariableModuleGlobal
->VariableGlobal
,
2313 (UINTN
) &Variable
->InDeletedTransitionPtr
->State
,
2317 if (!EFI_ERROR (Status
)) {
2318 if (!Variable
->Volatile
) {
2319 ASSERT (CacheVariable
->InDeletedTransitionPtr
!= NULL
);
2320 CacheVariable
->InDeletedTransitionPtr
->State
= State
;
2327 State
= Variable
->CurrPtr
->State
;
2328 State
&= VAR_DELETED
;
2330 Status
= UpdateVariableStore (
2331 &mVariableModuleGlobal
->VariableGlobal
,
2335 (UINTN
) &Variable
->CurrPtr
->State
,
2339 if (!EFI_ERROR (Status
) && !Variable
->Volatile
) {
2340 CacheVariable
->CurrPtr
->State
= State
;
2344 if (!EFI_ERROR (Status
)) {
2345 UpdateVariableInfo (VariableName
, VendorGuid
, Volatile
, FALSE
, TRUE
, FALSE
, FALSE
);
2347 FlushHobVariableToFlash (VariableName
, VendorGuid
);
2356 Check if a Unicode character is a hexadecimal character.
2358 This function checks if a Unicode character is a
2359 hexadecimal character. The valid hexadecimal character is
2360 L'0' to L'9', L'a' to L'f', or L'A' to L'F'.
2363 @param Char The character to check against.
2365 @retval TRUE If the Char is a hexadecmial character.
2366 @retval FALSE If the Char is not a hexadecmial character.
2371 IsHexaDecimalDigitCharacter (
2375 return (BOOLEAN
) ((Char
>= L
'0' && Char
<= L
'9') || (Char
>= L
'A' && Char
<= L
'F') || (Char
>= L
'a' && Char
<= L
'f'));
2380 This code checks if variable is hardware error record variable or not.
2382 According to UEFI spec, hardware error record variable should use the EFI_HARDWARE_ERROR_VARIABLE VendorGuid
2383 and have the L"HwErrRec####" name convention, #### is a printed hex value and no 0x or h is included in the hex value.
2385 @param VariableName Pointer to variable name.
2386 @param VendorGuid Variable Vendor Guid.
2388 @retval TRUE Variable is hardware error record variable.
2389 @retval FALSE Variable is not hardware error record variable.
2394 IsHwErrRecVariable (
2395 IN CHAR16
*VariableName
,
2396 IN EFI_GUID
*VendorGuid
2399 if (!CompareGuid (VendorGuid
, &gEfiHardwareErrorVariableGuid
) ||
2400 (StrLen (VariableName
) != StrLen (L
"HwErrRec####")) ||
2401 (StrnCmp(VariableName
, L
"HwErrRec", StrLen (L
"HwErrRec")) != 0) ||
2402 !IsHexaDecimalDigitCharacter (VariableName
[0x8]) ||
2403 !IsHexaDecimalDigitCharacter (VariableName
[0x9]) ||
2404 !IsHexaDecimalDigitCharacter (VariableName
[0xA]) ||
2405 !IsHexaDecimalDigitCharacter (VariableName
[0xB])) {
2413 This code checks if variable guid is global variable guid first.
2414 If yes, further check if variable name is in mGlobalVariableList or mGlobalVariableList2 and attributes matched.
2416 @param[in] VariableName Pointer to variable name.
2417 @param[in] VendorGuid Variable Vendor Guid.
2418 @param[in] Attributes Attributes of the variable.
2420 @retval EFI_SUCCESS Variable is not global variable, or Variable is global variable, variable name is in the lists and attributes matched.
2421 @retval EFI_INVALID_PARAMETER Variable is global variable, but variable name is not in the lists or attributes unmatched.
2426 CheckEfiGlobalVariable (
2427 IN CHAR16
*VariableName
,
2428 IN EFI_GUID
*VendorGuid
,
2429 IN UINT32 Attributes
2435 if (CompareGuid (VendorGuid
, &gEfiGlobalVariableGuid
)){
2437 // Try list 1, exactly match.
2439 for (Index
= 0; Index
< sizeof (mGlobalVariableList
)/sizeof (mGlobalVariableList
[0]); Index
++) {
2440 if ((StrCmp (mGlobalVariableList
[Index
].Name
, VariableName
) == 0) &&
2441 (Attributes
== 0 || (Attributes
& (~EFI_VARIABLE_APPEND_WRITE
)) == mGlobalVariableList
[Index
].Attributes
)) {
2449 NameLength
= StrLen (VariableName
) - 4;
2450 for (Index
= 0; Index
< sizeof (mGlobalVariableList2
)/sizeof (mGlobalVariableList2
[0]); Index
++) {
2451 if ((StrLen (VariableName
) == StrLen (mGlobalVariableList2
[Index
].Name
)) &&
2452 (StrnCmp (mGlobalVariableList2
[Index
].Name
, VariableName
, NameLength
) == 0) &&
2453 IsHexaDecimalDigitCharacter (VariableName
[NameLength
]) &&
2454 IsHexaDecimalDigitCharacter (VariableName
[NameLength
+ 1]) &&
2455 IsHexaDecimalDigitCharacter (VariableName
[NameLength
+ 2]) &&
2456 IsHexaDecimalDigitCharacter (VariableName
[NameLength
+ 3]) &&
2457 (Attributes
== 0 || (Attributes
& (~EFI_VARIABLE_APPEND_WRITE
)) == mGlobalVariableList2
[Index
].Attributes
)) {
2462 DEBUG ((EFI_D_INFO
, "[Variable]: set global variable with invalid variable name or attributes - %g:%s:%x\n", VendorGuid
, VariableName
, Attributes
));
2463 return EFI_INVALID_PARAMETER
;
2470 Mark a variable that will become read-only after leaving the DXE phase of execution.
2472 @param[in] This The VARIABLE_LOCK_PROTOCOL instance.
2473 @param[in] VariableName A pointer to the variable name that will be made read-only subsequently.
2474 @param[in] VendorGuid A pointer to the vendor GUID that will be made read-only subsequently.
2476 @retval EFI_SUCCESS The variable specified by the VariableName and the VendorGuid was marked
2477 as pending to be read-only.
2478 @retval EFI_INVALID_PARAMETER VariableName or VendorGuid is NULL.
2479 Or VariableName is an empty string.
2480 @retval EFI_ACCESS_DENIED EFI_END_OF_DXE_EVENT_GROUP_GUID or EFI_EVENT_GROUP_READY_TO_BOOT has
2481 already been signaled.
2482 @retval EFI_OUT_OF_RESOURCES There is not enough resource to hold the lock request.
2486 VariableLockRequestToLock (
2487 IN CONST EDKII_VARIABLE_LOCK_PROTOCOL
*This
,
2488 IN CHAR16
*VariableName
,
2489 IN EFI_GUID
*VendorGuid
2492 VARIABLE_ENTRY
*Entry
;
2494 if (VariableName
== NULL
|| VariableName
[0] == 0 || VendorGuid
== NULL
) {
2495 return EFI_INVALID_PARAMETER
;
2499 return EFI_ACCESS_DENIED
;
2502 Entry
= AllocateRuntimePool (sizeof (*Entry
) + StrSize (VariableName
));
2503 if (Entry
== NULL
) {
2504 return EFI_OUT_OF_RESOURCES
;
2507 DEBUG ((EFI_D_INFO
, "[Variable] Lock: %g:%s\n", VendorGuid
, VariableName
));
2509 AcquireLockOnlyAtBootTime(&mVariableModuleGlobal
->VariableGlobal
.VariableServicesLock
);
2511 Entry
->Name
= (CHAR16
*) (Entry
+ 1);
2512 StrCpy (Entry
->Name
, VariableName
);
2513 CopyGuid (&Entry
->Guid
, VendorGuid
);
2514 InsertTailList (&mLockedVariableList
, &Entry
->Link
);
2516 ReleaseLockOnlyAtBootTime (&mVariableModuleGlobal
->VariableGlobal
.VariableServicesLock
);
2522 This code checks if variable should be treated as read-only variable.
2524 @param[in] VariableName Name of the Variable.
2525 @param[in] VendorGuid GUID of the Variable.
2527 @retval TRUE This variable is read-only variable.
2528 @retval FALSE This variable is NOT read-only variable.
2532 IsReadOnlyVariable (
2533 IN CHAR16
*VariableName
,
2534 IN EFI_GUID
*VendorGuid
2537 if (CompareGuid (VendorGuid
, &gEfiGlobalVariableGuid
)) {
2538 if ((StrCmp (VariableName
, EFI_SETUP_MODE_NAME
) == 0) ||
2539 (StrCmp (VariableName
, EFI_SIGNATURE_SUPPORT_NAME
) == 0) ||
2540 (StrCmp (VariableName
, EFI_SECURE_BOOT_MODE_NAME
) == 0) ||
2541 (StrCmp (VariableName
, EFI_VENDOR_KEYS_VARIABLE_NAME
) == 0) ||
2542 (StrCmp (VariableName
, EFI_KEK_DEFAULT_VARIABLE_NAME
) == 0) ||
2543 (StrCmp (VariableName
, EFI_PK_DEFAULT_VARIABLE_NAME
) == 0) ||
2544 (StrCmp (VariableName
, EFI_DB_DEFAULT_VARIABLE_NAME
) == 0) ||
2545 (StrCmp (VariableName
, EFI_DBX_DEFAULT_VARIABLE_NAME
) == 0) ||
2546 (StrCmp (VariableName
, EFI_DBT_DEFAULT_VARIABLE_NAME
) == 0)) {
2556 This code finds variable in storage blocks (Volatile or Non-Volatile).
2558 Caution: This function may receive untrusted input.
2559 This function may be invoked in SMM mode, and datasize is external input.
2560 This function will do basic validation, before parse the data.
2562 @param VariableName Name of Variable to be found.
2563 @param VendorGuid Variable vendor GUID.
2564 @param Attributes Attribute value of the variable found.
2565 @param DataSize Size of Data found. If size is less than the
2566 data, this value contains the required size.
2567 @param Data Data pointer.
2569 @return EFI_INVALID_PARAMETER Invalid parameter.
2570 @return EFI_SUCCESS Find the specified variable.
2571 @return EFI_NOT_FOUND Not found.
2572 @return EFI_BUFFER_TO_SMALL DataSize is too small for the result.
2577 VariableServiceGetVariable (
2578 IN CHAR16
*VariableName
,
2579 IN EFI_GUID
*VendorGuid
,
2580 OUT UINT32
*Attributes OPTIONAL
,
2581 IN OUT UINTN
*DataSize
,
2586 VARIABLE_POINTER_TRACK Variable
;
2589 if (VariableName
== NULL
|| VendorGuid
== NULL
|| DataSize
== NULL
) {
2590 return EFI_INVALID_PARAMETER
;
2593 AcquireLockOnlyAtBootTime(&mVariableModuleGlobal
->VariableGlobal
.VariableServicesLock
);
2595 Status
= FindVariable (VariableName
, VendorGuid
, &Variable
, &mVariableModuleGlobal
->VariableGlobal
, FALSE
);
2596 if (Variable
.CurrPtr
== NULL
|| EFI_ERROR (Status
)) {
2603 VarDataSize
= DataSizeOfVariable (Variable
.CurrPtr
);
2604 ASSERT (VarDataSize
!= 0);
2606 if (*DataSize
>= VarDataSize
) {
2608 Status
= EFI_INVALID_PARAMETER
;
2612 CopyMem (Data
, GetVariableDataPtr (Variable
.CurrPtr
), VarDataSize
);
2613 if (Attributes
!= NULL
) {
2614 *Attributes
= Variable
.CurrPtr
->Attributes
;
2617 *DataSize
= VarDataSize
;
2618 UpdateVariableInfo (VariableName
, VendorGuid
, Variable
.Volatile
, TRUE
, FALSE
, FALSE
, FALSE
);
2620 Status
= EFI_SUCCESS
;
2623 *DataSize
= VarDataSize
;
2624 Status
= EFI_BUFFER_TOO_SMALL
;
2629 ReleaseLockOnlyAtBootTime (&mVariableModuleGlobal
->VariableGlobal
.VariableServicesLock
);
2637 This code Finds the Next available variable.
2639 Caution: This function may receive untrusted input.
2640 This function may be invoked in SMM mode. This function will do basic validation, before parse the data.
2642 @param VariableNameSize Size of the variable name.
2643 @param VariableName Pointer to variable name.
2644 @param VendorGuid Variable Vendor Guid.
2646 @return EFI_INVALID_PARAMETER Invalid parameter.
2647 @return EFI_SUCCESS Find the specified variable.
2648 @return EFI_NOT_FOUND Not found.
2649 @return EFI_BUFFER_TO_SMALL DataSize is too small for the result.
2654 VariableServiceGetNextVariableName (
2655 IN OUT UINTN
*VariableNameSize
,
2656 IN OUT CHAR16
*VariableName
,
2657 IN OUT EFI_GUID
*VendorGuid
2660 VARIABLE_STORE_TYPE Type
;
2661 VARIABLE_POINTER_TRACK Variable
;
2662 VARIABLE_POINTER_TRACK VariableInHob
;
2663 VARIABLE_POINTER_TRACK VariablePtrTrack
;
2666 VARIABLE_STORE_HEADER
*VariableStoreHeader
[VariableStoreTypeMax
];
2668 if (VariableNameSize
== NULL
|| VariableName
== NULL
|| VendorGuid
== NULL
) {
2669 return EFI_INVALID_PARAMETER
;
2672 AcquireLockOnlyAtBootTime(&mVariableModuleGlobal
->VariableGlobal
.VariableServicesLock
);
2674 Status
= FindVariable (VariableName
, VendorGuid
, &Variable
, &mVariableModuleGlobal
->VariableGlobal
, FALSE
);
2675 if (Variable
.CurrPtr
== NULL
|| EFI_ERROR (Status
)) {
2679 if (VariableName
[0] != 0) {
2681 // If variable name is not NULL, get next variable.
2683 Variable
.CurrPtr
= GetNextVariablePtr (Variable
.CurrPtr
);
2687 // 0: Volatile, 1: HOB, 2: Non-Volatile.
2688 // The index and attributes mapping must be kept in this order as FindVariable
2689 // makes use of this mapping to implement search algorithm.
2691 VariableStoreHeader
[VariableStoreTypeVolatile
] = (VARIABLE_STORE_HEADER
*) (UINTN
) mVariableModuleGlobal
->VariableGlobal
.VolatileVariableBase
;
2692 VariableStoreHeader
[VariableStoreTypeHob
] = (VARIABLE_STORE_HEADER
*) (UINTN
) mVariableModuleGlobal
->VariableGlobal
.HobVariableBase
;
2693 VariableStoreHeader
[VariableStoreTypeNv
] = mNvVariableCache
;
2697 // Switch from Volatile to HOB, to Non-Volatile.
2699 while ((Variable
.CurrPtr
>= Variable
.EndPtr
) ||
2700 (Variable
.CurrPtr
== NULL
) ||
2701 !IsValidVariableHeader (Variable
.CurrPtr
)
2704 // Find current storage index
2706 for (Type
= (VARIABLE_STORE_TYPE
) 0; Type
< VariableStoreTypeMax
; Type
++) {
2707 if ((VariableStoreHeader
[Type
] != NULL
) && (Variable
.StartPtr
== GetStartPointer (VariableStoreHeader
[Type
]))) {
2711 ASSERT (Type
< VariableStoreTypeMax
);
2713 // Switch to next storage
2715 for (Type
++; Type
< VariableStoreTypeMax
; Type
++) {
2716 if (VariableStoreHeader
[Type
] != NULL
) {
2721 // Capture the case that
2722 // 1. current storage is the last one, or
2723 // 2. no further storage
2725 if (Type
== VariableStoreTypeMax
) {
2726 Status
= EFI_NOT_FOUND
;
2729 Variable
.StartPtr
= GetStartPointer (VariableStoreHeader
[Type
]);
2730 Variable
.EndPtr
= GetEndPointer (VariableStoreHeader
[Type
]);
2731 Variable
.CurrPtr
= Variable
.StartPtr
;
2735 // Variable is found
2737 if (Variable
.CurrPtr
->State
== VAR_ADDED
|| Variable
.CurrPtr
->State
== (VAR_IN_DELETED_TRANSITION
& VAR_ADDED
)) {
2738 if (!AtRuntime () || ((Variable
.CurrPtr
->Attributes
& EFI_VARIABLE_RUNTIME_ACCESS
) != 0)) {
2739 if (Variable
.CurrPtr
->State
== (VAR_IN_DELETED_TRANSITION
& VAR_ADDED
)) {
2741 // If it is a IN_DELETED_TRANSITION variable,
2742 // and there is also a same ADDED one at the same time,
2745 VariablePtrTrack
.StartPtr
= Variable
.StartPtr
;
2746 VariablePtrTrack
.EndPtr
= Variable
.EndPtr
;
2747 Status
= FindVariableEx (
2748 GetVariableNamePtr (Variable
.CurrPtr
),
2749 &Variable
.CurrPtr
->VendorGuid
,
2753 if (!EFI_ERROR (Status
) && VariablePtrTrack
.CurrPtr
->State
== VAR_ADDED
) {
2754 Variable
.CurrPtr
= GetNextVariablePtr (Variable
.CurrPtr
);
2760 // Don't return NV variable when HOB overrides it
2762 if ((VariableStoreHeader
[VariableStoreTypeHob
] != NULL
) && (VariableStoreHeader
[VariableStoreTypeNv
] != NULL
) &&
2763 (Variable
.StartPtr
== GetStartPointer (VariableStoreHeader
[VariableStoreTypeNv
]))
2765 VariableInHob
.StartPtr
= GetStartPointer (VariableStoreHeader
[VariableStoreTypeHob
]);
2766 VariableInHob
.EndPtr
= GetEndPointer (VariableStoreHeader
[VariableStoreTypeHob
]);
2767 Status
= FindVariableEx (
2768 GetVariableNamePtr (Variable
.CurrPtr
),
2769 &Variable
.CurrPtr
->VendorGuid
,
2773 if (!EFI_ERROR (Status
)) {
2774 Variable
.CurrPtr
= GetNextVariablePtr (Variable
.CurrPtr
);
2779 VarNameSize
= NameSizeOfVariable (Variable
.CurrPtr
);
2780 ASSERT (VarNameSize
!= 0);
2782 if (VarNameSize
<= *VariableNameSize
) {
2783 CopyMem (VariableName
, GetVariableNamePtr (Variable
.CurrPtr
), VarNameSize
);
2784 CopyMem (VendorGuid
, &Variable
.CurrPtr
->VendorGuid
, sizeof (EFI_GUID
));
2785 Status
= EFI_SUCCESS
;
2787 Status
= EFI_BUFFER_TOO_SMALL
;
2790 *VariableNameSize
= VarNameSize
;
2795 Variable
.CurrPtr
= GetNextVariablePtr (Variable
.CurrPtr
);
2799 ReleaseLockOnlyAtBootTime (&mVariableModuleGlobal
->VariableGlobal
.VariableServicesLock
);
2805 This code sets variable in storage blocks (Volatile or Non-Volatile).
2807 Caution: This function may receive untrusted input.
2808 This function may be invoked in SMM mode, and datasize and data are external input.
2809 This function will do basic validation, before parse the data.
2810 This function will parse the authentication carefully to avoid security issues, like
2811 buffer overflow, integer overflow.
2812 This function will check attribute carefully to avoid authentication bypass.
2814 @param VariableName Name of Variable to be found.
2815 @param VendorGuid Variable vendor GUID.
2816 @param Attributes Attribute value of the variable found
2817 @param DataSize Size of Data found. If size is less than the
2818 data, this value contains the required size.
2819 @param Data Data pointer.
2821 @return EFI_INVALID_PARAMETER Invalid parameter.
2822 @return EFI_SUCCESS Set successfully.
2823 @return EFI_OUT_OF_RESOURCES Resource not enough to set variable.
2824 @return EFI_NOT_FOUND Not found.
2825 @return EFI_WRITE_PROTECTED Variable is read-only.
2830 VariableServiceSetVariable (
2831 IN CHAR16
*VariableName
,
2832 IN EFI_GUID
*VendorGuid
,
2833 IN UINT32 Attributes
,
2838 VARIABLE_POINTER_TRACK Variable
;
2840 VARIABLE_HEADER
*NextVariable
;
2841 EFI_PHYSICAL_ADDRESS Point
;
2844 VARIABLE_ENTRY
*Entry
;
2847 // Check input parameters.
2849 if (VariableName
== NULL
|| VariableName
[0] == 0 || VendorGuid
== NULL
) {
2850 return EFI_INVALID_PARAMETER
;
2853 if (IsReadOnlyVariable (VariableName
, VendorGuid
)) {
2854 return EFI_WRITE_PROTECTED
;
2857 if (DataSize
!= 0 && Data
== NULL
) {
2858 return EFI_INVALID_PARAMETER
;
2862 // Check for reserverd bit in variable attribute.
2864 if ((Attributes
& (~EFI_VARIABLE_ATTRIBUTES_MASK
)) != 0) {
2865 return EFI_INVALID_PARAMETER
;
2869 // Make sure if runtime bit is set, boot service bit is set also.
2871 if ((Attributes
& (EFI_VARIABLE_RUNTIME_ACCESS
| EFI_VARIABLE_BOOTSERVICE_ACCESS
)) == EFI_VARIABLE_RUNTIME_ACCESS
) {
2872 return EFI_INVALID_PARAMETER
;
2876 // EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS and EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS attribute
2877 // cannot be set both.
2879 if (((Attributes
& EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS
) == EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS
)
2880 && ((Attributes
& EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS
) == EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS
)) {
2881 return EFI_INVALID_PARAMETER
;
2884 if ((Attributes
& EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS
) == EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS
) {
2885 if (DataSize
< AUTHINFO_SIZE
) {
2887 // Try to write Authenticated Variable without AuthInfo.
2889 return EFI_SECURITY_VIOLATION
;
2891 PayloadSize
= DataSize
- AUTHINFO_SIZE
;
2892 } else if ((Attributes
& EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS
) == EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS
) {
2894 // Sanity check for EFI_VARIABLE_AUTHENTICATION_2 descriptor.
2896 if (DataSize
< OFFSET_OF_AUTHINFO2_CERT_DATA
||
2897 ((EFI_VARIABLE_AUTHENTICATION_2
*) Data
)->AuthInfo
.Hdr
.dwLength
> DataSize
- (OFFSET_OF (EFI_VARIABLE_AUTHENTICATION_2
, AuthInfo
)) ||
2898 ((EFI_VARIABLE_AUTHENTICATION_2
*) Data
)->AuthInfo
.Hdr
.dwLength
< OFFSET_OF (WIN_CERTIFICATE_UEFI_GUID
, CertData
)) {
2899 return EFI_SECURITY_VIOLATION
;
2901 PayloadSize
= DataSize
- AUTHINFO2_SIZE (Data
);
2903 PayloadSize
= DataSize
;
2906 if ((UINTN
)(~0) - PayloadSize
< StrSize(VariableName
)){
2908 // Prevent whole variable size overflow
2910 return EFI_INVALID_PARAMETER
;
2914 // The size of the VariableName, including the Unicode Null in bytes plus
2915 // the DataSize is limited to maximum size of PcdGet32 (PcdMaxHardwareErrorVariableSize)
2916 // bytes for HwErrRec, and PcdGet32 (PcdMaxVariableSize) bytes for the others.
2918 if ((Attributes
& EFI_VARIABLE_HARDWARE_ERROR_RECORD
) == EFI_VARIABLE_HARDWARE_ERROR_RECORD
) {
2919 if (StrSize (VariableName
) + PayloadSize
> PcdGet32 (PcdMaxHardwareErrorVariableSize
) - sizeof (VARIABLE_HEADER
)) {
2920 return EFI_INVALID_PARAMETER
;
2922 if (!IsHwErrRecVariable(VariableName
, VendorGuid
)) {
2923 return EFI_INVALID_PARAMETER
;
2927 // The size of the VariableName, including the Unicode Null in bytes plus
2928 // the DataSize is limited to maximum size of PcdGet32 (PcdMaxVariableSize) bytes.
2930 if (StrSize (VariableName
) + PayloadSize
> PcdGet32 (PcdMaxVariableSize
) - sizeof (VARIABLE_HEADER
)) {
2931 return EFI_INVALID_PARAMETER
;
2935 Status
= CheckEfiGlobalVariable (VariableName
, VendorGuid
, Attributes
);
2936 if (EFI_ERROR (Status
)) {
2940 AcquireLockOnlyAtBootTime(&mVariableModuleGlobal
->VariableGlobal
.VariableServicesLock
);
2943 // Consider reentrant in MCA/INIT/NMI. It needs be reupdated.
2945 if (1 < InterlockedIncrement (&mVariableModuleGlobal
->VariableGlobal
.ReentrantState
)) {
2946 Point
= mVariableModuleGlobal
->VariableGlobal
.NonVolatileVariableBase
;
2948 // Parse non-volatile variable data and get last variable offset.
2950 NextVariable
= GetStartPointer ((VARIABLE_STORE_HEADER
*) (UINTN
) Point
);
2951 while ((NextVariable
< GetEndPointer ((VARIABLE_STORE_HEADER
*) (UINTN
) Point
))
2952 && IsValidVariableHeader (NextVariable
)) {
2953 NextVariable
= GetNextVariablePtr (NextVariable
);
2955 mVariableModuleGlobal
->NonVolatileLastVariableOffset
= (UINTN
) NextVariable
- (UINTN
) Point
;
2958 if (mEndOfDxe
&& mEnableLocking
) {
2960 // Treat the variables listed in the forbidden variable list as read-only after leaving DXE phase.
2962 for ( Link
= GetFirstNode (&mLockedVariableList
)
2963 ; !IsNull (&mLockedVariableList
, Link
)
2964 ; Link
= GetNextNode (&mLockedVariableList
, Link
)
2966 Entry
= BASE_CR (Link
, VARIABLE_ENTRY
, Link
);
2967 if (CompareGuid (&Entry
->Guid
, VendorGuid
) && (StrCmp (Entry
->Name
, VariableName
) == 0)) {
2968 Status
= EFI_WRITE_PROTECTED
;
2969 DEBUG ((EFI_D_INFO
, "[Variable]: Changing readonly variable after leaving DXE phase - %g:%s\n", VendorGuid
, VariableName
));
2976 // Check whether the input variable is already existed.
2978 Status
= FindVariable (VariableName
, VendorGuid
, &Variable
, &mVariableModuleGlobal
->VariableGlobal
, TRUE
);
2979 if (!EFI_ERROR (Status
)) {
2980 if (((Variable
.CurrPtr
->Attributes
& EFI_VARIABLE_RUNTIME_ACCESS
) == 0) && AtRuntime ()) {
2981 Status
= EFI_WRITE_PROTECTED
;
2984 if (Attributes
!= 0 && (Attributes
& (~EFI_VARIABLE_APPEND_WRITE
)) != Variable
.CurrPtr
->Attributes
) {
2986 // If a preexisting variable is rewritten with different attributes, SetVariable() shall not
2987 // modify the variable and shall return EFI_INVALID_PARAMETER. Two exceptions to this rule:
2988 // 1. No access attributes specified
2989 // 2. The only attribute differing is EFI_VARIABLE_APPEND_WRITE
2991 Status
= EFI_INVALID_PARAMETER
;
2997 // Hook the operation of setting PlatformLangCodes/PlatformLang and LangCodes/Lang.
2999 Status
= AutoUpdateLangVariable (VariableName
, Data
, DataSize
);
3000 if (EFI_ERROR (Status
)) {
3002 // The auto update operation failed, directly return to avoid inconsistency between PlatformLang and Lang.
3008 // Process PK, KEK, Sigdb seperately.
3010 if (CompareGuid (VendorGuid
, &gEfiGlobalVariableGuid
) && (StrCmp (VariableName
, EFI_PLATFORM_KEY_NAME
) == 0)){
3011 Status
= ProcessVarWithPk (VariableName
, VendorGuid
, Data
, DataSize
, &Variable
, Attributes
, TRUE
);
3012 } else if (CompareGuid (VendorGuid
, &gEfiGlobalVariableGuid
) && (StrCmp (VariableName
, EFI_KEY_EXCHANGE_KEY_NAME
) == 0)) {
3013 Status
= ProcessVarWithPk (VariableName
, VendorGuid
, Data
, DataSize
, &Variable
, Attributes
, FALSE
);
3014 } else if (CompareGuid (VendorGuid
, &gEfiImageSecurityDatabaseGuid
) &&
3015 ((StrCmp (VariableName
, EFI_IMAGE_SECURITY_DATABASE
) == 0) || (StrCmp (VariableName
, EFI_IMAGE_SECURITY_DATABASE1
) == 0))) {
3016 Status
= ProcessVarWithPk (VariableName
, VendorGuid
, Data
, DataSize
, &Variable
, Attributes
, FALSE
);
3017 if (EFI_ERROR (Status
)) {
3018 Status
= ProcessVarWithKek (VariableName
, VendorGuid
, Data
, DataSize
, &Variable
, Attributes
);
3021 Status
= ProcessVariable (VariableName
, VendorGuid
, Data
, DataSize
, &Variable
, Attributes
);
3025 InterlockedDecrement (&mVariableModuleGlobal
->VariableGlobal
.ReentrantState
);
3026 ReleaseLockOnlyAtBootTime (&mVariableModuleGlobal
->VariableGlobal
.VariableServicesLock
);
3028 if (!AtRuntime ()) {
3029 if (!EFI_ERROR (Status
)) {
3042 This code returns information about the EFI variables.
3044 Caution: This function may receive untrusted input.
3045 This function may be invoked in SMM mode. This function will do basic validation, before parse the data.
3047 @param Attributes Attributes bitmask to specify the type of variables
3048 on which to return information.
3049 @param MaximumVariableStorageSize Pointer to the maximum size of the storage space available
3050 for the EFI variables associated with the attributes specified.
3051 @param RemainingVariableStorageSize Pointer to the remaining size of the storage space available
3052 for EFI variables associated with the attributes specified.
3053 @param MaximumVariableSize Pointer to the maximum size of an individual EFI variables
3054 associated with the attributes specified.
3056 @return EFI_INVALID_PARAMETER An invalid combination of attribute bits was supplied.
3057 @return EFI_SUCCESS Query successfully.
3058 @return EFI_UNSUPPORTED The attribute is not supported on this platform.
3063 VariableServiceQueryVariableInfo (
3064 IN UINT32 Attributes
,
3065 OUT UINT64
*MaximumVariableStorageSize
,
3066 OUT UINT64
*RemainingVariableStorageSize
,
3067 OUT UINT64
*MaximumVariableSize
3070 VARIABLE_HEADER
*Variable
;
3071 VARIABLE_HEADER
*NextVariable
;
3072 UINT64 VariableSize
;
3073 VARIABLE_STORE_HEADER
*VariableStoreHeader
;
3074 UINT64 CommonVariableTotalSize
;
3075 UINT64 HwErrVariableTotalSize
;
3077 CommonVariableTotalSize
= 0;
3078 HwErrVariableTotalSize
= 0;
3080 if(MaximumVariableStorageSize
== NULL
|| RemainingVariableStorageSize
== NULL
|| MaximumVariableSize
== NULL
|| Attributes
== 0) {
3081 return EFI_INVALID_PARAMETER
;
3084 if((Attributes
& (EFI_VARIABLE_NON_VOLATILE
| EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_RUNTIME_ACCESS
| EFI_VARIABLE_HARDWARE_ERROR_RECORD
)) == 0) {
3086 // Make sure the Attributes combination is supported by the platform.
3088 return EFI_UNSUPPORTED
;
3089 } else if ((Attributes
& (EFI_VARIABLE_RUNTIME_ACCESS
| EFI_VARIABLE_BOOTSERVICE_ACCESS
)) == EFI_VARIABLE_RUNTIME_ACCESS
) {
3091 // Make sure if runtime bit is set, boot service bit is set also.
3093 return EFI_INVALID_PARAMETER
;
3094 } else if (AtRuntime () && ((Attributes
& EFI_VARIABLE_RUNTIME_ACCESS
) == 0)) {
3096 // Make sure RT Attribute is set if we are in Runtime phase.
3098 return EFI_INVALID_PARAMETER
;
3099 } else if ((Attributes
& (EFI_VARIABLE_NON_VOLATILE
| EFI_VARIABLE_HARDWARE_ERROR_RECORD
)) == EFI_VARIABLE_HARDWARE_ERROR_RECORD
) {
3101 // Make sure Hw Attribute is set with NV.
3103 return EFI_INVALID_PARAMETER
;
3106 AcquireLockOnlyAtBootTime(&mVariableModuleGlobal
->VariableGlobal
.VariableServicesLock
);
3108 if((Attributes
& EFI_VARIABLE_NON_VOLATILE
) == 0) {
3110 // Query is Volatile related.
3112 VariableStoreHeader
= (VARIABLE_STORE_HEADER
*) ((UINTN
) mVariableModuleGlobal
->VariableGlobal
.VolatileVariableBase
);
3115 // Query is Non-Volatile related.
3117 VariableStoreHeader
= mNvVariableCache
;
3121 // Now let's fill *MaximumVariableStorageSize *RemainingVariableStorageSize
3122 // with the storage size (excluding the storage header size).
3124 *MaximumVariableStorageSize
= VariableStoreHeader
->Size
- sizeof (VARIABLE_STORE_HEADER
);
3127 // Harware error record variable needs larger size.
3129 if ((Attributes
& (EFI_VARIABLE_NON_VOLATILE
| EFI_VARIABLE_HARDWARE_ERROR_RECORD
)) == (EFI_VARIABLE_NON_VOLATILE
| EFI_VARIABLE_HARDWARE_ERROR_RECORD
)) {
3130 *MaximumVariableStorageSize
= PcdGet32 (PcdHwErrStorageSize
);
3131 *MaximumVariableSize
= PcdGet32 (PcdMaxHardwareErrorVariableSize
) - sizeof (VARIABLE_HEADER
);
3133 if ((Attributes
& EFI_VARIABLE_NON_VOLATILE
) != 0) {
3134 ASSERT (PcdGet32 (PcdHwErrStorageSize
) < VariableStoreHeader
->Size
);
3135 *MaximumVariableStorageSize
= VariableStoreHeader
->Size
- sizeof (VARIABLE_STORE_HEADER
) - PcdGet32 (PcdHwErrStorageSize
);
3139 // Let *MaximumVariableSize be PcdGet32 (PcdMaxVariableSize) with the exception of the variable header size.
3141 *MaximumVariableSize
= PcdGet32 (PcdMaxVariableSize
) - sizeof (VARIABLE_HEADER
);
3145 // Point to the starting address of the variables.
3147 Variable
= GetStartPointer (VariableStoreHeader
);
3150 // Now walk through the related variable store.
3152 while ((Variable
< GetEndPointer (VariableStoreHeader
)) && IsValidVariableHeader (Variable
)) {
3153 NextVariable
= GetNextVariablePtr (Variable
);
3154 VariableSize
= (UINT64
) (UINTN
) NextVariable
- (UINT64
) (UINTN
) Variable
;
3158 // We don't take the state of the variables in mind
3159 // when calculating RemainingVariableStorageSize,
3160 // since the space occupied by variables not marked with
3161 // VAR_ADDED is not allowed to be reclaimed in Runtime.
3163 if ((Variable
->Attributes
& EFI_VARIABLE_HARDWARE_ERROR_RECORD
) == EFI_VARIABLE_HARDWARE_ERROR_RECORD
) {
3164 HwErrVariableTotalSize
+= VariableSize
;
3166 CommonVariableTotalSize
+= VariableSize
;
3170 // Only care about Variables with State VAR_ADDED, because
3171 // the space not marked as VAR_ADDED is reclaimable now.
3173 if (Variable
->State
== VAR_ADDED
) {
3174 if ((Variable
->Attributes
& EFI_VARIABLE_HARDWARE_ERROR_RECORD
) == EFI_VARIABLE_HARDWARE_ERROR_RECORD
) {
3175 HwErrVariableTotalSize
+= VariableSize
;
3177 CommonVariableTotalSize
+= VariableSize
;
3183 // Go to the next one.
3185 Variable
= NextVariable
;
3188 if ((Attributes
& EFI_VARIABLE_HARDWARE_ERROR_RECORD
) == EFI_VARIABLE_HARDWARE_ERROR_RECORD
){
3189 *RemainingVariableStorageSize
= *MaximumVariableStorageSize
- HwErrVariableTotalSize
;
3191 *RemainingVariableStorageSize
= *MaximumVariableStorageSize
- CommonVariableTotalSize
;
3194 if (*RemainingVariableStorageSize
< sizeof (VARIABLE_HEADER
)) {
3195 *MaximumVariableSize
= 0;
3196 } else if ((*RemainingVariableStorageSize
- sizeof (VARIABLE_HEADER
)) < *MaximumVariableSize
) {
3197 *MaximumVariableSize
= *RemainingVariableStorageSize
- sizeof (VARIABLE_HEADER
);
3200 ReleaseLockOnlyAtBootTime (&mVariableModuleGlobal
->VariableGlobal
.VariableServicesLock
);
3206 This function reclaims variable storage if free size is below the threshold.
3208 Caution: This function may be invoked at SMM mode.
3209 Care must be taken to make sure not security issue.
3218 UINTN CommonVariableSpace
;
3219 UINTN RemainingCommonVariableSpace
;
3220 UINTN RemainingHwErrVariableSpace
;
3222 Status
= EFI_SUCCESS
;
3224 CommonVariableSpace
= ((VARIABLE_STORE_HEADER
*) ((UINTN
) (mVariableModuleGlobal
->VariableGlobal
.NonVolatileVariableBase
)))->Size
- sizeof (VARIABLE_STORE_HEADER
) - PcdGet32(PcdHwErrStorageSize
); //Allowable max size of common variable storage space
3226 RemainingCommonVariableSpace
= CommonVariableSpace
- mVariableModuleGlobal
->CommonVariableTotalSize
;
3228 RemainingHwErrVariableSpace
= PcdGet32 (PcdHwErrStorageSize
) - mVariableModuleGlobal
->HwErrVariableTotalSize
;
3230 // Check if the free area is blow a threshold.
3232 if ((RemainingCommonVariableSpace
< PcdGet32 (PcdMaxVariableSize
))
3233 || ((PcdGet32 (PcdHwErrStorageSize
) != 0) &&
3234 (RemainingHwErrVariableSpace
< PcdGet32 (PcdMaxHardwareErrorVariableSize
)))){
3236 mVariableModuleGlobal
->VariableGlobal
.NonVolatileVariableBase
,
3237 &mVariableModuleGlobal
->NonVolatileLastVariableOffset
,
3244 ASSERT_EFI_ERROR (Status
);
3249 Init non-volatile variable store.
3251 @retval EFI_SUCCESS Function successfully executed.
3252 @retval EFI_OUT_OF_RESOURCES Fail to allocate enough memory resource.
3253 @retval EFI_VOLUME_CORRUPTED Variable Store or Firmware Volume for Variable Store is corrupted.
3257 InitNonVolatileVariableStore (
3261 EFI_FIRMWARE_VOLUME_HEADER
*FvHeader
;
3262 VARIABLE_HEADER
*NextVariable
;
3263 EFI_PHYSICAL_ADDRESS VariableStoreBase
;
3264 UINT64 VariableStoreLength
;
3266 EFI_HOB_GUID_TYPE
*GuidHob
;
3267 EFI_PHYSICAL_ADDRESS NvStorageBase
;
3268 UINT8
*NvStorageData
;
3269 UINT32 NvStorageSize
;
3270 FAULT_TOLERANT_WRITE_LAST_WRITE_DATA
*FtwLastWriteData
;
3271 UINT32 BackUpOffset
;
3274 mVariableModuleGlobal
->FvbInstance
= NULL
;
3277 // Note that in EdkII variable driver implementation, Hardware Error Record type variable
3278 // is stored with common variable in the same NV region. So the platform integrator should
3279 // ensure that the value of PcdHwErrStorageSize is less than or equal to the value of
3280 // PcdFlashNvStorageVariableSize.
3282 ASSERT (PcdGet32 (PcdHwErrStorageSize
) <= PcdGet32 (PcdFlashNvStorageVariableSize
));
3285 // Allocate runtime memory used for a memory copy of the FLASH region.
3286 // Keep the memory and the FLASH in sync as updates occur.
3288 NvStorageSize
= PcdGet32 (PcdFlashNvStorageVariableSize
);
3289 NvStorageData
= AllocateRuntimeZeroPool (NvStorageSize
);
3290 if (NvStorageData
== NULL
) {
3291 return EFI_OUT_OF_RESOURCES
;
3294 NvStorageBase
= (EFI_PHYSICAL_ADDRESS
) PcdGet64 (PcdFlashNvStorageVariableBase64
);
3295 if (NvStorageBase
== 0) {
3296 NvStorageBase
= (EFI_PHYSICAL_ADDRESS
) PcdGet32 (PcdFlashNvStorageVariableBase
);
3299 // Copy NV storage data to the memory buffer.
3301 CopyMem (NvStorageData
, (UINT8
*) (UINTN
) NvStorageBase
, NvStorageSize
);
3304 // Check the FTW last write data hob.
3306 GuidHob
= GetFirstGuidHob (&gEdkiiFaultTolerantWriteGuid
);
3307 if (GuidHob
!= NULL
) {
3308 FtwLastWriteData
= (FAULT_TOLERANT_WRITE_LAST_WRITE_DATA
*) GET_GUID_HOB_DATA (GuidHob
);
3309 if (FtwLastWriteData
->TargetAddress
== NvStorageBase
) {
3310 DEBUG ((EFI_D_INFO
, "Variable: NV storage is backed up in spare block: 0x%x\n", (UINTN
) FtwLastWriteData
->SpareAddress
));
3312 // Copy the backed up NV storage data to the memory buffer from spare block.
3314 CopyMem (NvStorageData
, (UINT8
*) (UINTN
) (FtwLastWriteData
->SpareAddress
), NvStorageSize
);
3315 } else if ((FtwLastWriteData
->TargetAddress
> NvStorageBase
) &&
3316 (FtwLastWriteData
->TargetAddress
< (NvStorageBase
+ NvStorageSize
))) {
3318 // Flash NV storage from the Offset is backed up in spare block.
3320 BackUpOffset
= (UINT32
) (FtwLastWriteData
->TargetAddress
- NvStorageBase
);
3321 BackUpSize
= NvStorageSize
- BackUpOffset
;
3322 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
));
3324 // Copy the partial backed up NV storage data to the memory buffer from spare block.
3326 CopyMem (NvStorageData
+ BackUpOffset
, (UINT8
*) (UINTN
) FtwLastWriteData
->SpareAddress
, BackUpSize
);
3330 FvHeader
= (EFI_FIRMWARE_VOLUME_HEADER
*) NvStorageData
;
3333 // Check if the Firmware Volume is not corrupted
3335 if ((FvHeader
->Signature
!= EFI_FVH_SIGNATURE
) || (!CompareGuid (&gEfiSystemNvDataFvGuid
, &FvHeader
->FileSystemGuid
))) {
3336 FreePool (NvStorageData
);
3337 DEBUG ((EFI_D_ERROR
, "Firmware Volume for Variable Store is corrupted\n"));
3338 return EFI_VOLUME_CORRUPTED
;
3341 VariableStoreBase
= (EFI_PHYSICAL_ADDRESS
) ((UINTN
) FvHeader
+ FvHeader
->HeaderLength
);
3342 VariableStoreLength
= (UINT64
) (NvStorageSize
- FvHeader
->HeaderLength
);
3344 mVariableModuleGlobal
->VariableGlobal
.NonVolatileVariableBase
= VariableStoreBase
;
3345 mNvVariableCache
= (VARIABLE_STORE_HEADER
*) (UINTN
) VariableStoreBase
;
3346 if (GetVariableStoreStatus (mNvVariableCache
) != EfiValid
) {
3347 FreePool (NvStorageData
);
3348 DEBUG((EFI_D_ERROR
, "Variable Store header is corrupted\n"));
3349 return EFI_VOLUME_CORRUPTED
;
3351 ASSERT(mNvVariableCache
->Size
== VariableStoreLength
);
3354 // The max variable or hardware error variable size should be < variable store size.
3356 ASSERT(MAX (PcdGet32 (PcdMaxVariableSize
), PcdGet32 (PcdMaxHardwareErrorVariableSize
)) < VariableStoreLength
);
3359 // Parse non-volatile variable data and get last variable offset.
3361 NextVariable
= GetStartPointer ((VARIABLE_STORE_HEADER
*)(UINTN
)VariableStoreBase
);
3362 while (IsValidVariableHeader (NextVariable
)) {
3363 VariableSize
= NextVariable
->NameSize
+ NextVariable
->DataSize
+ sizeof (VARIABLE_HEADER
);
3364 if ((NextVariable
->Attributes
& (EFI_VARIABLE_NON_VOLATILE
| EFI_VARIABLE_HARDWARE_ERROR_RECORD
)) == (EFI_VARIABLE_NON_VOLATILE
| EFI_VARIABLE_HARDWARE_ERROR_RECORD
)) {
3365 mVariableModuleGlobal
->HwErrVariableTotalSize
+= HEADER_ALIGN (VariableSize
);
3367 mVariableModuleGlobal
->CommonVariableTotalSize
+= HEADER_ALIGN (VariableSize
);
3370 NextVariable
= GetNextVariablePtr (NextVariable
);
3372 mVariableModuleGlobal
->NonVolatileLastVariableOffset
= (UINTN
) NextVariable
- (UINTN
) VariableStoreBase
;
3378 Flush the HOB variable to flash.
3380 @param[in] VariableName Name of variable has been updated or deleted.
3381 @param[in] VendorGuid Guid of variable has been updated or deleted.
3385 FlushHobVariableToFlash (
3386 IN CHAR16
*VariableName
,
3387 IN EFI_GUID
*VendorGuid
3391 VARIABLE_STORE_HEADER
*VariableStoreHeader
;
3392 VARIABLE_HEADER
*Variable
;
3399 // Flush the HOB variable to flash.
3401 if (mVariableModuleGlobal
->VariableGlobal
.HobVariableBase
!= 0) {
3402 VariableStoreHeader
= (VARIABLE_STORE_HEADER
*) (UINTN
) mVariableModuleGlobal
->VariableGlobal
.HobVariableBase
;
3404 // Set HobVariableBase to 0, it can avoid SetVariable to call back.
3406 mVariableModuleGlobal
->VariableGlobal
.HobVariableBase
= 0;
3407 for ( Variable
= GetStartPointer (VariableStoreHeader
)
3408 ; (Variable
< GetEndPointer (VariableStoreHeader
) && IsValidVariableHeader (Variable
))
3409 ; Variable
= GetNextVariablePtr (Variable
)
3411 if (Variable
->State
!= VAR_ADDED
) {
3413 // The HOB variable has been set to DELETED state in local.
3417 ASSERT ((Variable
->Attributes
& EFI_VARIABLE_NON_VOLATILE
) != 0);
3418 if (VendorGuid
== NULL
|| VariableName
== NULL
||
3419 !CompareGuid (VendorGuid
, &Variable
->VendorGuid
) ||
3420 StrCmp (VariableName
, GetVariableNamePtr (Variable
)) != 0) {
3421 VariableData
= GetVariableDataPtr (Variable
);
3422 Status
= VariableServiceSetVariable (
3423 GetVariableNamePtr (Variable
),
3424 &Variable
->VendorGuid
,
3425 Variable
->Attributes
,
3429 DEBUG ((EFI_D_INFO
, "Variable driver flush the HOB variable to flash: %g %s %r\n", &Variable
->VendorGuid
, GetVariableNamePtr (Variable
), Status
));
3432 // The updated or deleted variable is matched with the HOB variable.
3433 // Don't break here because we will try to set other HOB variables
3434 // since this variable could be set successfully.
3436 Status
= EFI_SUCCESS
;
3438 if (!EFI_ERROR (Status
)) {
3440 // If set variable successful, or the updated or deleted variable is matched with the HOB variable,
3441 // set the HOB variable to DELETED state in local.
3443 DEBUG ((EFI_D_INFO
, "Variable driver set the HOB variable to DELETED state in local: %g %s\n", &Variable
->VendorGuid
, GetVariableNamePtr (Variable
)));
3444 Variable
->State
&= VAR_DELETED
;
3451 // We still have HOB variable(s) not flushed in flash.
3453 mVariableModuleGlobal
->VariableGlobal
.HobVariableBase
= (EFI_PHYSICAL_ADDRESS
) (UINTN
) VariableStoreHeader
;
3456 // All HOB variables have been flushed in flash.
3458 DEBUG ((EFI_D_INFO
, "Variable driver: all HOB variables have been flushed in flash.\n"));
3459 if (!AtRuntime ()) {
3460 FreePool ((VOID
*) VariableStoreHeader
);
3468 Initializes variable write service after FTW was ready.
3470 @retval EFI_SUCCESS Function successfully executed.
3471 @retval Others Fail to initialize the variable service.
3475 VariableWriteServiceInitialize (
3480 VARIABLE_STORE_HEADER
*VariableStoreHeader
;
3483 EFI_PHYSICAL_ADDRESS VariableStoreBase
;
3484 EFI_PHYSICAL_ADDRESS NvStorageBase
;
3486 NvStorageBase
= (EFI_PHYSICAL_ADDRESS
) PcdGet64 (PcdFlashNvStorageVariableBase64
);
3487 if (NvStorageBase
== 0) {
3488 NvStorageBase
= (EFI_PHYSICAL_ADDRESS
) PcdGet32 (PcdFlashNvStorageVariableBase
);
3490 VariableStoreBase
= NvStorageBase
+ (((EFI_FIRMWARE_VOLUME_HEADER
*)(UINTN
)(NvStorageBase
))->HeaderLength
);
3493 // Let NonVolatileVariableBase point to flash variable store base directly after FTW ready.
3495 mVariableModuleGlobal
->VariableGlobal
.NonVolatileVariableBase
= VariableStoreBase
;
3496 VariableStoreHeader
= (VARIABLE_STORE_HEADER
*)(UINTN
)VariableStoreBase
;
3499 // Check if the free area is really free.
3501 for (Index
= mVariableModuleGlobal
->NonVolatileLastVariableOffset
; Index
< VariableStoreHeader
->Size
; Index
++) {
3502 Data
= ((UINT8
*) mNvVariableCache
)[Index
];
3505 // There must be something wrong in variable store, do reclaim operation.
3508 mVariableModuleGlobal
->VariableGlobal
.NonVolatileVariableBase
,
3509 &mVariableModuleGlobal
->NonVolatileLastVariableOffset
,
3516 if (EFI_ERROR (Status
)) {
3523 FlushHobVariableToFlash (NULL
, NULL
);
3526 // Authenticated variable initialize.
3528 Status
= AutenticatedVariableServiceInitialize ();
3535 Initializes variable store area for non-volatile and volatile variable.
3537 @retval EFI_SUCCESS Function successfully executed.
3538 @retval EFI_OUT_OF_RESOURCES Fail to allocate enough memory resource.
3542 VariableCommonInitialize (
3547 VARIABLE_STORE_HEADER
*VolatileVariableStore
;
3548 VARIABLE_STORE_HEADER
*VariableStoreHeader
;
3549 UINT64 VariableStoreLength
;
3551 EFI_HOB_GUID_TYPE
*GuidHob
;
3554 // Allocate runtime memory for variable driver global structure.
3556 mVariableModuleGlobal
= AllocateRuntimeZeroPool (sizeof (VARIABLE_MODULE_GLOBAL
));
3557 if (mVariableModuleGlobal
== NULL
) {
3558 return EFI_OUT_OF_RESOURCES
;
3561 InitializeLock (&mVariableModuleGlobal
->VariableGlobal
.VariableServicesLock
, TPL_NOTIFY
);
3564 // Get HOB variable store.
3566 GuidHob
= GetFirstGuidHob (&gEfiAuthenticatedVariableGuid
);
3567 if (GuidHob
!= NULL
) {
3568 VariableStoreHeader
= GET_GUID_HOB_DATA (GuidHob
);
3569 VariableStoreLength
= (UINT64
) (GuidHob
->Header
.HobLength
- sizeof (EFI_HOB_GUID_TYPE
));
3570 if (GetVariableStoreStatus (VariableStoreHeader
) == EfiValid
) {
3571 mVariableModuleGlobal
->VariableGlobal
.HobVariableBase
= (EFI_PHYSICAL_ADDRESS
) (UINTN
) AllocateRuntimeCopyPool ((UINTN
) VariableStoreLength
, (VOID
*) VariableStoreHeader
);
3572 if (mVariableModuleGlobal
->VariableGlobal
.HobVariableBase
== 0) {
3573 FreePool (mVariableModuleGlobal
);
3574 return EFI_OUT_OF_RESOURCES
;
3577 DEBUG ((EFI_D_ERROR
, "HOB Variable Store header is corrupted!\n"));
3582 // Allocate memory for volatile variable store, note that there is a scratch space to store scratch data.
3584 ScratchSize
= MAX (PcdGet32 (PcdMaxVariableSize
), PcdGet32 (PcdMaxHardwareErrorVariableSize
));
3585 VolatileVariableStore
= AllocateRuntimePool (PcdGet32 (PcdVariableStoreSize
) + ScratchSize
);
3586 if (VolatileVariableStore
== NULL
) {
3587 if (mVariableModuleGlobal
->VariableGlobal
.HobVariableBase
!= 0) {
3588 FreePool ((VOID
*) (UINTN
) mVariableModuleGlobal
->VariableGlobal
.HobVariableBase
);
3590 FreePool (mVariableModuleGlobal
);
3591 return EFI_OUT_OF_RESOURCES
;
3594 SetMem (VolatileVariableStore
, PcdGet32 (PcdVariableStoreSize
) + ScratchSize
, 0xff);
3597 // Initialize Variable Specific Data.
3599 mVariableModuleGlobal
->VariableGlobal
.VolatileVariableBase
= (EFI_PHYSICAL_ADDRESS
) (UINTN
) VolatileVariableStore
;
3600 mVariableModuleGlobal
->VolatileLastVariableOffset
= (UINTN
) GetStartPointer (VolatileVariableStore
) - (UINTN
) VolatileVariableStore
;
3602 CopyGuid (&VolatileVariableStore
->Signature
, &gEfiAuthenticatedVariableGuid
);
3603 VolatileVariableStore
->Size
= PcdGet32 (PcdVariableStoreSize
);
3604 VolatileVariableStore
->Format
= VARIABLE_STORE_FORMATTED
;
3605 VolatileVariableStore
->State
= VARIABLE_STORE_HEALTHY
;
3606 VolatileVariableStore
->Reserved
= 0;
3607 VolatileVariableStore
->Reserved1
= 0;
3610 // Init non-volatile variable store.
3612 Status
= InitNonVolatileVariableStore ();
3613 if (EFI_ERROR (Status
)) {
3614 if (mVariableModuleGlobal
->VariableGlobal
.HobVariableBase
!= 0) {
3615 FreePool ((VOID
*) (UINTN
) mVariableModuleGlobal
->VariableGlobal
.HobVariableBase
);
3617 FreePool (mVariableModuleGlobal
);
3618 FreePool (VolatileVariableStore
);
3626 Get the proper fvb handle and/or fvb protocol by the given Flash address.
3628 @param[in] Address The Flash address.
3629 @param[out] FvbHandle In output, if it is not NULL, it points to the proper FVB handle.
3630 @param[out] FvbProtocol In output, if it is not NULL, it points to the proper FVB protocol.
3634 GetFvbInfoByAddress (
3635 IN EFI_PHYSICAL_ADDRESS Address
,
3636 OUT EFI_HANDLE
*FvbHandle OPTIONAL
,
3637 OUT EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
**FvbProtocol OPTIONAL
3641 EFI_HANDLE
*HandleBuffer
;
3644 EFI_PHYSICAL_ADDRESS FvbBaseAddress
;
3645 EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*Fvb
;
3646 EFI_FIRMWARE_VOLUME_HEADER
*FwVolHeader
;
3647 EFI_FVB_ATTRIBUTES_2 Attributes
;
3650 // Get all FVB handles.
3652 Status
= GetFvbCountAndBuffer (&HandleCount
, &HandleBuffer
);
3653 if (EFI_ERROR (Status
)) {
3654 return EFI_NOT_FOUND
;
3658 // Get the FVB to access variable store.
3661 for (Index
= 0; Index
< HandleCount
; Index
+= 1, Status
= EFI_NOT_FOUND
, Fvb
= NULL
) {
3662 Status
= GetFvbByHandle (HandleBuffer
[Index
], &Fvb
);
3663 if (EFI_ERROR (Status
)) {
3664 Status
= EFI_NOT_FOUND
;
3669 // Ensure this FVB protocol supported Write operation.
3671 Status
= Fvb
->GetAttributes (Fvb
, &Attributes
);
3672 if (EFI_ERROR (Status
) || ((Attributes
& EFI_FVB2_WRITE_STATUS
) == 0)) {
3677 // Compare the address and select the right one.
3679 Status
= Fvb
->GetPhysicalAddress (Fvb
, &FvbBaseAddress
);
3680 if (EFI_ERROR (Status
)) {
3684 FwVolHeader
= (EFI_FIRMWARE_VOLUME_HEADER
*) ((UINTN
) FvbBaseAddress
);
3685 if ((Address
>= FvbBaseAddress
) && (Address
< (FvbBaseAddress
+ FwVolHeader
->FvLength
))) {
3686 if (FvbHandle
!= NULL
) {
3687 *FvbHandle
= HandleBuffer
[Index
];
3689 if (FvbProtocol
!= NULL
) {
3692 Status
= EFI_SUCCESS
;
3696 FreePool (HandleBuffer
);
3699 Status
= EFI_NOT_FOUND
;