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) 2006 - 2020, Intel Corporation. All rights reserved.<BR>
20 (C) Copyright 2015-2018 Hewlett Packard Enterprise Development LP<BR>
21 Copyright (c) Microsoft Corporation.<BR>
23 SPDX-License-Identifier: BSD-2-Clause-Patent
28 #include "VariableNonVolatile.h"
29 #include "VariableParsing.h"
30 #include "VariableRuntimeCache.h"
32 VARIABLE_MODULE_GLOBAL
*mVariableModuleGlobal
;
35 /// Define a memory cache that improves the search performance for a variable.
36 /// For EmuNvMode == TRUE, it will be equal to NonVolatileVariableBase.
38 VARIABLE_STORE_HEADER
*mNvVariableCache
= NULL
;
41 /// Memory cache of Fv Header.
43 EFI_FIRMWARE_VOLUME_HEADER
*mNvFvHeaderCache
= NULL
;
46 /// The memory entry used for variable statistics data.
48 VARIABLE_INFO_ENTRY
*gVariableInfo
= NULL
;
51 /// The flag to indicate whether the platform has left the DXE phase of execution.
53 BOOLEAN mEndOfDxe
= FALSE
;
56 /// It indicates the var check request source.
57 /// In the implementation, DXE is regarded as untrusted, and SMM is trusted.
59 VAR_CHECK_REQUEST_SOURCE mRequestSource
= VarCheckFromUntrusted
;
62 // It will record the current boot error flag before EndOfDxe.
64 VAR_ERROR_FLAG mCurrentBootVarErrFlag
= VAR_ERROR_FLAG_NO_ERROR
;
66 VARIABLE_ENTRY_PROPERTY mVariableEntryProperty
[] = {
68 &gEdkiiVarErrorFlagGuid
,
71 VAR_CHECK_VARIABLE_PROPERTY_REVISION
,
72 VAR_CHECK_VARIABLE_PROPERTY_READ_ONLY
,
73 VARIABLE_ATTRIBUTE_NV_BS_RT
,
74 sizeof (VAR_ERROR_FLAG
),
75 sizeof (VAR_ERROR_FLAG
)
80 AUTH_VAR_LIB_CONTEXT_IN mAuthContextIn
= {
81 AUTH_VAR_LIB_CONTEXT_IN_STRUCT_VERSION
,
83 // StructSize, TO BE FILLED
87 // MaxAuthVariableSize, TO BE FILLED
90 VariableExLibFindVariable
,
91 VariableExLibFindNextVariable
,
92 VariableExLibUpdateVariable
,
93 VariableExLibGetScratchBuffer
,
94 VariableExLibCheckRemainingSpaceForConsistency
,
95 VariableExLibAtRuntime
,
98 AUTH_VAR_LIB_CONTEXT_OUT mAuthContextOut
;
102 This function writes data to the FWH at the correct LBA even if the LBAs
105 @param Global Pointer to VARAIBLE_GLOBAL structure.
106 @param Volatile Point out the Variable is Volatile or Non-Volatile.
107 @param SetByIndex TRUE if target pointer is given as index.
108 FALSE if target pointer is absolute.
109 @param Fvb Pointer to the writable FVB protocol.
110 @param DataPtrIndex Pointer to the Data from the end of VARIABLE_STORE_HEADER
112 @param DataSize Size of data to be written.
113 @param Buffer Pointer to the buffer from which data is written.
115 @retval EFI_INVALID_PARAMETER Parameters not valid.
116 @retval EFI_UNSUPPORTED Fvb is a NULL for Non-Volatile variable update.
117 @retval EFI_OUT_OF_RESOURCES The remaining size is not enough.
118 @retval EFI_SUCCESS Variable store successfully updated.
122 UpdateVariableStore (
123 IN VARIABLE_GLOBAL
*Global
,
125 IN BOOLEAN SetByIndex
,
126 IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*Fvb
,
127 IN UINTN DataPtrIndex
,
132 EFI_FV_BLOCK_MAP_ENTRY
*PtrBlockMapEntry
;
140 VARIABLE_STORE_HEADER
*VolatileBase
;
141 EFI_PHYSICAL_ADDRESS FvVolHdr
;
142 EFI_PHYSICAL_ADDRESS DataPtr
;
146 DataPtr
= DataPtrIndex
;
149 // Check if the Data is Volatile.
151 if (!Volatile
&& !mVariableModuleGlobal
->VariableGlobal
.EmuNvMode
) {
153 return EFI_UNSUPPORTED
;
156 Status
= Fvb
->GetPhysicalAddress (Fvb
, &FvVolHdr
);
157 ASSERT_EFI_ERROR (Status
);
160 // Data Pointer should point to the actual Address where data is to be
164 DataPtr
+= mVariableModuleGlobal
->VariableGlobal
.NonVolatileVariableBase
;
167 if ((DataPtr
+ DataSize
) > (FvVolHdr
+ mNvFvHeaderCache
->FvLength
)) {
168 return EFI_OUT_OF_RESOURCES
;
172 // Data Pointer should point to the actual Address where data is to be
176 VolatileBase
= (VARIABLE_STORE_HEADER
*)((UINTN
)mVariableModuleGlobal
->VariableGlobal
.VolatileVariableBase
);
178 DataPtr
+= mVariableModuleGlobal
->VariableGlobal
.VolatileVariableBase
;
181 if ((DataPtr
+ DataSize
) > ((UINTN
)VolatileBase
+ VolatileBase
->Size
)) {
182 return EFI_OUT_OF_RESOURCES
;
186 // Emulated non-volatile variable mode.
189 DataPtr
+= (UINTN
)mNvVariableCache
;
192 if ((DataPtr
+ DataSize
) > ((UINTN
)mNvVariableCache
+ mNvVariableCache
->Size
)) {
193 return EFI_OUT_OF_RESOURCES
;
198 // If Volatile/Emulated Non-volatile Variable just do a simple mem copy.
200 CopyMem ((UINT8
*)(UINTN
)DataPtr
, Buffer
, DataSize
);
205 // If we are here we are dealing with Non-Volatile Variables.
207 LinearOffset
= (UINTN
)FvVolHdr
;
208 CurrWritePtr
= (UINTN
)DataPtr
;
209 CurrWriteSize
= DataSize
;
213 if (CurrWritePtr
< LinearOffset
) {
214 return EFI_INVALID_PARAMETER
;
217 for (PtrBlockMapEntry
= mNvFvHeaderCache
->BlockMap
; PtrBlockMapEntry
->NumBlocks
!= 0; PtrBlockMapEntry
++) {
218 for (BlockIndex2
= 0; BlockIndex2
< PtrBlockMapEntry
->NumBlocks
; BlockIndex2
++) {
220 // Check to see if the Variable Writes are spanning through multiple
223 if ((CurrWritePtr
>= LinearOffset
) && (CurrWritePtr
< LinearOffset
+ PtrBlockMapEntry
->Length
)) {
224 if ((CurrWritePtr
+ CurrWriteSize
) <= (LinearOffset
+ PtrBlockMapEntry
->Length
)) {
225 Status
= Fvb
->Write (
228 (UINTN
)(CurrWritePtr
- LinearOffset
),
234 Size
= (UINT32
)(LinearOffset
+ PtrBlockMapEntry
->Length
- CurrWritePtr
);
235 Status
= Fvb
->Write (
238 (UINTN
)(CurrWritePtr
- LinearOffset
),
242 if (EFI_ERROR (Status
)) {
246 CurrWritePtr
= LinearOffset
+ PtrBlockMapEntry
->Length
;
247 CurrBuffer
= CurrBuffer
+ Size
;
248 CurrWriteSize
= CurrWriteSize
- Size
;
252 LinearOffset
+= PtrBlockMapEntry
->Length
;
261 Record variable error flag.
263 @param[in] Flag Variable error flag to record.
264 @param[in] VariableName Name of variable.
265 @param[in] VendorGuid Guid of variable.
266 @param[in] Attributes Attributes of the variable.
267 @param[in] VariableSize Size of the variable.
272 IN VAR_ERROR_FLAG Flag
,
273 IN CHAR16
*VariableName
,
274 IN EFI_GUID
*VendorGuid
,
275 IN UINT32 Attributes
,
276 IN UINTN VariableSize
280 VARIABLE_POINTER_TRACK Variable
;
281 VAR_ERROR_FLAG
*VarErrFlag
;
282 VAR_ERROR_FLAG TempFlag
;
285 DEBUG ((DEBUG_ERROR
, "RecordVarErrorFlag (0x%02x) %s:%g - 0x%08x - 0x%x\n", Flag
, VariableName
, VendorGuid
, Attributes
, VariableSize
));
286 if (Flag
== VAR_ERROR_FLAG_SYSTEM_ERROR
) {
288 DEBUG ((DEBUG_ERROR
, "CommonRuntimeVariableSpace = 0x%x - CommonVariableTotalSize = 0x%x\n", mVariableModuleGlobal
->CommonRuntimeVariableSpace
, mVariableModuleGlobal
->CommonVariableTotalSize
));
290 DEBUG ((DEBUG_ERROR
, "CommonVariableSpace = 0x%x - CommonVariableTotalSize = 0x%x\n", mVariableModuleGlobal
->CommonVariableSpace
, mVariableModuleGlobal
->CommonVariableTotalSize
));
293 DEBUG ((DEBUG_ERROR
, "CommonMaxUserVariableSpace = 0x%x - CommonUserVariableTotalSize = 0x%x\n", mVariableModuleGlobal
->CommonMaxUserVariableSpace
, mVariableModuleGlobal
->CommonUserVariableTotalSize
));
300 // Before EndOfDxe, just record the current boot variable error flag to local variable,
301 // and leave the variable error flag in NV flash as the last boot variable error flag.
302 // After EndOfDxe in InitializeVarErrorFlag (), the variable error flag in NV flash
303 // will be initialized to this local current boot variable error flag.
305 mCurrentBootVarErrFlag
&= Flag
;
310 // Record error flag (it should have be initialized).
312 Status
= FindVariable (
314 &gEdkiiVarErrorFlagGuid
,
316 &mVariableModuleGlobal
->VariableGlobal
,
319 if (!EFI_ERROR (Status
)) {
320 VarErrFlag
= (VAR_ERROR_FLAG
*)GetVariableDataPtr (Variable
.CurrPtr
, mVariableModuleGlobal
->VariableGlobal
.AuthFormat
);
321 TempFlag
= *VarErrFlag
;
323 if (TempFlag
== *VarErrFlag
) {
327 Status
= UpdateVariableStore (
328 &mVariableModuleGlobal
->VariableGlobal
,
331 mVariableModuleGlobal
->FvbInstance
,
332 (UINTN
)VarErrFlag
- (UINTN
)mNvVariableCache
+ (UINTN
)mVariableModuleGlobal
->VariableGlobal
.NonVolatileVariableBase
,
336 if (!EFI_ERROR (Status
)) {
338 // Update the data in NV cache.
340 *VarErrFlag
= TempFlag
;
341 Status
= SynchronizeRuntimeVariableCache (
342 &mVariableModuleGlobal
->VariableGlobal
.VariableRuntimeCacheContext
.VariableRuntimeNvCache
,
344 mNvVariableCache
->Size
346 ASSERT_EFI_ERROR (Status
);
352 Initialize variable error flag.
354 Before EndOfDxe, the variable indicates the last boot variable error flag,
355 then it means the last boot variable error flag must be got before EndOfDxe.
356 After EndOfDxe, the variable indicates the current boot variable error flag,
357 then it means the current boot variable error flag must be got after EndOfDxe.
361 InitializeVarErrorFlag (
366 VARIABLE_POINTER_TRACK Variable
;
368 VAR_ERROR_FLAG VarErrFlag
;
374 Flag
= mCurrentBootVarErrFlag
;
375 DEBUG ((DEBUG_INFO
, "Initialize variable error flag (%02x)\n", Flag
));
377 Status
= FindVariable (
379 &gEdkiiVarErrorFlagGuid
,
381 &mVariableModuleGlobal
->VariableGlobal
,
384 if (!EFI_ERROR (Status
)) {
385 VarErrFlag
= *((VAR_ERROR_FLAG
*)GetVariableDataPtr (Variable
.CurrPtr
, mVariableModuleGlobal
->VariableGlobal
.AuthFormat
));
386 if (VarErrFlag
== Flag
) {
393 &gEdkiiVarErrorFlagGuid
,
396 VARIABLE_ATTRIBUTE_NV_BS_RT
,
407 @param[in] Variable Pointer to variable header.
409 @retval TRUE User variable.
410 @retval FALSE System variable.
415 IN VARIABLE_HEADER
*Variable
418 VAR_CHECK_VARIABLE_PROPERTY Property
;
421 // Only after End Of Dxe, the variables belong to system variable are fixed.
422 // If PcdMaxUserNvStorageVariableSize is 0, it means user variable share the same NV storage with system variable,
423 // then no need to check if the variable is user variable or not specially.
425 if (mEndOfDxe
&& (mVariableModuleGlobal
->CommonMaxUserVariableSpace
!= mVariableModuleGlobal
->CommonVariableSpace
)) {
426 if (VarCheckLibVariablePropertyGet (
427 GetVariableNamePtr (Variable
, mVariableModuleGlobal
->VariableGlobal
.AuthFormat
),
428 GetVendorGuidPtr (Variable
, mVariableModuleGlobal
->VariableGlobal
.AuthFormat
),
440 Calculate common user variable total size.
444 CalculateCommonUserVariableTotalSize (
448 VARIABLE_HEADER
*Variable
;
449 VARIABLE_HEADER
*NextVariable
;
451 VAR_CHECK_VARIABLE_PROPERTY Property
;
454 // Only after End Of Dxe, the variables belong to system variable are fixed.
455 // If PcdMaxUserNvStorageVariableSize is 0, it means user variable share the same NV storage with system variable,
456 // then no need to calculate the common user variable total size specially.
458 if (mEndOfDxe
&& (mVariableModuleGlobal
->CommonMaxUserVariableSpace
!= mVariableModuleGlobal
->CommonVariableSpace
)) {
459 Variable
= GetStartPointer (mNvVariableCache
);
460 while (IsValidVariableHeader (Variable
, GetEndPointer (mNvVariableCache
))) {
461 NextVariable
= GetNextVariablePtr (Variable
, mVariableModuleGlobal
->VariableGlobal
.AuthFormat
);
462 VariableSize
= (UINTN
)NextVariable
- (UINTN
)Variable
;
463 if ((Variable
->Attributes
& EFI_VARIABLE_HARDWARE_ERROR_RECORD
) != EFI_VARIABLE_HARDWARE_ERROR_RECORD
) {
464 if (VarCheckLibVariablePropertyGet (
465 GetVariableNamePtr (Variable
, mVariableModuleGlobal
->VariableGlobal
.AuthFormat
),
466 GetVendorGuidPtr (Variable
, mVariableModuleGlobal
->VariableGlobal
.AuthFormat
),
471 // No property, it is user variable.
473 mVariableModuleGlobal
->CommonUserVariableTotalSize
+= VariableSize
;
477 Variable
= NextVariable
;
483 Initialize variable quota.
487 InitializeVariableQuota (
495 InitializeVarErrorFlag ();
496 CalculateCommonUserVariableTotalSize ();
501 Variable store garbage collection and reclaim operation.
503 @param[in] VariableBase Base address of variable store.
504 @param[out] LastVariableOffset Offset of last variable.
505 @param[in] IsVolatile The variable store is volatile or not;
506 if it is non-volatile, need FTW.
507 @param[in, out] UpdatingPtrTrack Pointer to updating variable pointer track structure.
508 @param[in] NewVariable Pointer to new variable.
509 @param[in] NewVariableSize New variable size.
511 @return EFI_SUCCESS Reclaim operation has finished successfully.
512 @return EFI_OUT_OF_RESOURCES No enough memory resources or variable space.
513 @return Others Unexpect error happened during reclaim operation.
518 IN EFI_PHYSICAL_ADDRESS VariableBase
,
519 OUT UINTN
*LastVariableOffset
,
520 IN BOOLEAN IsVolatile
,
521 IN OUT VARIABLE_POINTER_TRACK
*UpdatingPtrTrack
,
522 IN VARIABLE_HEADER
*NewVariable
,
523 IN UINTN NewVariableSize
526 VARIABLE_HEADER
*Variable
;
527 VARIABLE_HEADER
*AddedVariable
;
528 VARIABLE_HEADER
*NextVariable
;
529 VARIABLE_HEADER
*NextAddedVariable
;
530 VARIABLE_STORE_HEADER
*VariableStoreHeader
;
532 UINTN MaximumBufferSize
;
540 EFI_STATUS DoneStatus
;
541 UINTN CommonVariableTotalSize
;
542 UINTN CommonUserVariableTotalSize
;
543 UINTN HwErrVariableTotalSize
;
544 VARIABLE_HEADER
*UpdatingVariable
;
545 VARIABLE_HEADER
*UpdatingInDeletedTransition
;
548 AuthFormat
= mVariableModuleGlobal
->VariableGlobal
.AuthFormat
;
549 UpdatingVariable
= NULL
;
550 UpdatingInDeletedTransition
= NULL
;
551 if (UpdatingPtrTrack
!= NULL
) {
552 UpdatingVariable
= UpdatingPtrTrack
->CurrPtr
;
553 UpdatingInDeletedTransition
= UpdatingPtrTrack
->InDeletedTransitionPtr
;
556 VariableStoreHeader
= (VARIABLE_STORE_HEADER
*)((UINTN
)VariableBase
);
558 CommonVariableTotalSize
= 0;
559 CommonUserVariableTotalSize
= 0;
560 HwErrVariableTotalSize
= 0;
562 if (IsVolatile
|| mVariableModuleGlobal
->VariableGlobal
.EmuNvMode
) {
564 // Start Pointers for the variable.
566 Variable
= GetStartPointer (VariableStoreHeader
);
567 MaximumBufferSize
= sizeof (VARIABLE_STORE_HEADER
);
569 while (IsValidVariableHeader (Variable
, GetEndPointer (VariableStoreHeader
))) {
570 NextVariable
= GetNextVariablePtr (Variable
, AuthFormat
);
571 if (((Variable
->State
== VAR_ADDED
) || (Variable
->State
== (VAR_IN_DELETED_TRANSITION
& VAR_ADDED
))) &&
572 (Variable
!= UpdatingVariable
) &&
573 (Variable
!= UpdatingInDeletedTransition
)
576 VariableSize
= (UINTN
)NextVariable
- (UINTN
)Variable
;
577 MaximumBufferSize
+= VariableSize
;
580 Variable
= NextVariable
;
583 if (NewVariable
!= NULL
) {
585 // Add the new variable size.
587 MaximumBufferSize
+= NewVariableSize
;
591 // Reserve the 1 Bytes with Oxff to identify the
592 // end of the variable buffer.
594 MaximumBufferSize
+= 1;
595 ValidBuffer
= AllocatePool (MaximumBufferSize
);
596 if (ValidBuffer
== NULL
) {
597 return EFI_OUT_OF_RESOURCES
;
601 // For NV variable reclaim, don't allocate pool here and just use mNvVariableCache
602 // as the buffer to reduce SMRAM consumption for SMM variable driver.
604 MaximumBufferSize
= mNvVariableCache
->Size
;
605 ValidBuffer
= (UINT8
*)mNvVariableCache
;
608 SetMem (ValidBuffer
, MaximumBufferSize
, 0xff);
611 // Copy variable store header.
613 CopyMem (ValidBuffer
, VariableStoreHeader
, sizeof (VARIABLE_STORE_HEADER
));
614 CurrPtr
= (UINT8
*)GetStartPointer ((VARIABLE_STORE_HEADER
*)ValidBuffer
);
617 // Reinstall all ADDED variables as long as they are not identical to Updating Variable.
619 Variable
= GetStartPointer (VariableStoreHeader
);
620 while (IsValidVariableHeader (Variable
, GetEndPointer (VariableStoreHeader
))) {
621 NextVariable
= GetNextVariablePtr (Variable
, AuthFormat
);
622 if ((Variable
!= UpdatingVariable
) && (Variable
->State
== VAR_ADDED
)) {
623 VariableSize
= (UINTN
)NextVariable
- (UINTN
)Variable
;
624 CopyMem (CurrPtr
, (UINT8
*)Variable
, VariableSize
);
625 CurrPtr
+= VariableSize
;
626 if ((!IsVolatile
) && ((Variable
->Attributes
& EFI_VARIABLE_HARDWARE_ERROR_RECORD
) == EFI_VARIABLE_HARDWARE_ERROR_RECORD
)) {
627 HwErrVariableTotalSize
+= VariableSize
;
628 } else if ((!IsVolatile
) && ((Variable
->Attributes
& EFI_VARIABLE_HARDWARE_ERROR_RECORD
) != EFI_VARIABLE_HARDWARE_ERROR_RECORD
)) {
629 CommonVariableTotalSize
+= VariableSize
;
630 if (IsUserVariable (Variable
)) {
631 CommonUserVariableTotalSize
+= VariableSize
;
636 Variable
= NextVariable
;
640 // Reinstall all in delete transition variables.
642 Variable
= GetStartPointer (VariableStoreHeader
);
643 while (IsValidVariableHeader (Variable
, GetEndPointer (VariableStoreHeader
))) {
644 NextVariable
= GetNextVariablePtr (Variable
, AuthFormat
);
645 if ((Variable
!= UpdatingVariable
) && (Variable
!= UpdatingInDeletedTransition
) && (Variable
->State
== (VAR_IN_DELETED_TRANSITION
& VAR_ADDED
))) {
647 // Buffer has cached all ADDED variable.
648 // Per IN_DELETED variable, we have to guarantee that
649 // no ADDED one in previous buffer.
653 AddedVariable
= GetStartPointer ((VARIABLE_STORE_HEADER
*)ValidBuffer
);
654 while (IsValidVariableHeader (AddedVariable
, GetEndPointer ((VARIABLE_STORE_HEADER
*)ValidBuffer
))) {
655 NextAddedVariable
= GetNextVariablePtr (AddedVariable
, AuthFormat
);
656 NameSize
= NameSizeOfVariable (AddedVariable
, AuthFormat
);
658 GetVendorGuidPtr (AddedVariable
, AuthFormat
),
659 GetVendorGuidPtr (Variable
, AuthFormat
)
660 ) && (NameSize
== NameSizeOfVariable (Variable
, AuthFormat
)))
662 Point0
= (VOID
*)GetVariableNamePtr (AddedVariable
, AuthFormat
);
663 Point1
= (VOID
*)GetVariableNamePtr (Variable
, AuthFormat
);
664 if (CompareMem (Point0
, Point1
, NameSize
) == 0) {
670 AddedVariable
= NextAddedVariable
;
675 // Promote VAR_IN_DELETED_TRANSITION to VAR_ADDED.
677 VariableSize
= (UINTN
)NextVariable
- (UINTN
)Variable
;
678 CopyMem (CurrPtr
, (UINT8
*)Variable
, VariableSize
);
679 ((VARIABLE_HEADER
*)CurrPtr
)->State
= VAR_ADDED
;
680 CurrPtr
+= VariableSize
;
681 if ((!IsVolatile
) && ((Variable
->Attributes
& EFI_VARIABLE_HARDWARE_ERROR_RECORD
) == EFI_VARIABLE_HARDWARE_ERROR_RECORD
)) {
682 HwErrVariableTotalSize
+= VariableSize
;
683 } else if ((!IsVolatile
) && ((Variable
->Attributes
& EFI_VARIABLE_HARDWARE_ERROR_RECORD
) != EFI_VARIABLE_HARDWARE_ERROR_RECORD
)) {
684 CommonVariableTotalSize
+= VariableSize
;
685 if (IsUserVariable (Variable
)) {
686 CommonUserVariableTotalSize
+= VariableSize
;
692 Variable
= NextVariable
;
696 // Install the new variable if it is not NULL.
698 if (NewVariable
!= NULL
) {
699 if (((UINTN
)CurrPtr
- (UINTN
)ValidBuffer
) + NewVariableSize
> VariableStoreHeader
->Size
) {
701 // No enough space to store the new variable.
703 Status
= EFI_OUT_OF_RESOURCES
;
708 if ((NewVariable
->Attributes
& EFI_VARIABLE_HARDWARE_ERROR_RECORD
) == EFI_VARIABLE_HARDWARE_ERROR_RECORD
) {
709 HwErrVariableTotalSize
+= NewVariableSize
;
710 } else if ((NewVariable
->Attributes
& EFI_VARIABLE_HARDWARE_ERROR_RECORD
) != EFI_VARIABLE_HARDWARE_ERROR_RECORD
) {
711 CommonVariableTotalSize
+= NewVariableSize
;
712 if (IsUserVariable (NewVariable
)) {
713 CommonUserVariableTotalSize
+= NewVariableSize
;
717 if ((HwErrVariableTotalSize
> PcdGet32 (PcdHwErrStorageSize
)) ||
718 (CommonVariableTotalSize
> mVariableModuleGlobal
->CommonVariableSpace
) ||
719 (CommonUserVariableTotalSize
> mVariableModuleGlobal
->CommonMaxUserVariableSpace
))
722 // No enough space to store the new variable by NV or NV+HR attribute.
724 Status
= EFI_OUT_OF_RESOURCES
;
729 CopyMem (CurrPtr
, (UINT8
*)NewVariable
, NewVariableSize
);
730 ((VARIABLE_HEADER
*)CurrPtr
)->State
= VAR_ADDED
;
731 if (UpdatingVariable
!= NULL
) {
732 UpdatingPtrTrack
->CurrPtr
= (VARIABLE_HEADER
*)((UINTN
)UpdatingPtrTrack
->StartPtr
+ ((UINTN
)CurrPtr
- (UINTN
)GetStartPointer ((VARIABLE_STORE_HEADER
*)ValidBuffer
)));
733 UpdatingPtrTrack
->InDeletedTransitionPtr
= NULL
;
736 CurrPtr
+= NewVariableSize
;
739 if (IsVolatile
|| mVariableModuleGlobal
->VariableGlobal
.EmuNvMode
) {
741 // If volatile/emulated non-volatile variable store, just copy valid buffer.
743 SetMem ((UINT8
*)(UINTN
)VariableBase
, VariableStoreHeader
->Size
, 0xff);
744 CopyMem ((UINT8
*)(UINTN
)VariableBase
, ValidBuffer
, (UINTN
)CurrPtr
- (UINTN
)ValidBuffer
);
745 *LastVariableOffset
= (UINTN
)CurrPtr
- (UINTN
)ValidBuffer
;
748 // Emulated non-volatile variable mode.
750 mVariableModuleGlobal
->HwErrVariableTotalSize
= HwErrVariableTotalSize
;
751 mVariableModuleGlobal
->CommonVariableTotalSize
= CommonVariableTotalSize
;
752 mVariableModuleGlobal
->CommonUserVariableTotalSize
= CommonUserVariableTotalSize
;
755 Status
= EFI_SUCCESS
;
758 // If non-volatile variable store, perform FTW here.
760 Status
= FtwVariableSpace (
762 (VARIABLE_STORE_HEADER
*)ValidBuffer
764 if (!EFI_ERROR (Status
)) {
765 *LastVariableOffset
= (UINTN
)CurrPtr
- (UINTN
)ValidBuffer
;
766 mVariableModuleGlobal
->HwErrVariableTotalSize
= HwErrVariableTotalSize
;
767 mVariableModuleGlobal
->CommonVariableTotalSize
= CommonVariableTotalSize
;
768 mVariableModuleGlobal
->CommonUserVariableTotalSize
= CommonUserVariableTotalSize
;
770 mVariableModuleGlobal
->HwErrVariableTotalSize
= 0;
771 mVariableModuleGlobal
->CommonVariableTotalSize
= 0;
772 mVariableModuleGlobal
->CommonUserVariableTotalSize
= 0;
773 Variable
= GetStartPointer ((VARIABLE_STORE_HEADER
*)(UINTN
)VariableBase
);
774 while (IsValidVariableHeader (Variable
, GetEndPointer ((VARIABLE_STORE_HEADER
*)(UINTN
)VariableBase
))) {
775 NextVariable
= GetNextVariablePtr (Variable
, AuthFormat
);
776 VariableSize
= (UINTN
)NextVariable
- (UINTN
)Variable
;
777 if ((Variable
->Attributes
& EFI_VARIABLE_HARDWARE_ERROR_RECORD
) == EFI_VARIABLE_HARDWARE_ERROR_RECORD
) {
778 mVariableModuleGlobal
->HwErrVariableTotalSize
+= VariableSize
;
779 } else if ((Variable
->Attributes
& EFI_VARIABLE_HARDWARE_ERROR_RECORD
) != EFI_VARIABLE_HARDWARE_ERROR_RECORD
) {
780 mVariableModuleGlobal
->CommonVariableTotalSize
+= VariableSize
;
781 if (IsUserVariable (Variable
)) {
782 mVariableModuleGlobal
->CommonUserVariableTotalSize
+= VariableSize
;
786 Variable
= NextVariable
;
789 *LastVariableOffset
= (UINTN
)Variable
- (UINTN
)VariableBase
;
794 DoneStatus
= EFI_SUCCESS
;
795 if (IsVolatile
|| mVariableModuleGlobal
->VariableGlobal
.EmuNvMode
) {
796 DoneStatus
= SynchronizeRuntimeVariableCache (
797 &mVariableModuleGlobal
->VariableGlobal
.VariableRuntimeCacheContext
.VariableRuntimeVolatileCache
,
799 VariableStoreHeader
->Size
801 ASSERT_EFI_ERROR (DoneStatus
);
802 FreePool (ValidBuffer
);
805 // For NV variable reclaim, we use mNvVariableCache as the buffer, so copy the data back.
807 CopyMem (mNvVariableCache
, (UINT8
*)(UINTN
)VariableBase
, VariableStoreHeader
->Size
);
808 DoneStatus
= SynchronizeRuntimeVariableCache (
809 &mVariableModuleGlobal
->VariableGlobal
.VariableRuntimeCacheContext
.VariableRuntimeNvCache
,
811 VariableStoreHeader
->Size
813 ASSERT_EFI_ERROR (DoneStatus
);
816 if (!EFI_ERROR (Status
) && EFI_ERROR (DoneStatus
)) {
824 Finds variable in storage blocks of volatile and non-volatile storage areas.
826 This code finds variable in storage blocks of volatile and non-volatile storage areas.
827 If VariableName is an empty string, then we just return the first
828 qualified variable without comparing VariableName and VendorGuid.
829 If IgnoreRtCheck is TRUE, then we ignore the EFI_VARIABLE_RUNTIME_ACCESS attribute check
830 at runtime when searching existing variable, only VariableName and VendorGuid are compared.
831 Otherwise, variables without EFI_VARIABLE_RUNTIME_ACCESS are not visible at runtime.
833 @param[in] VariableName Name of the variable to be found.
834 @param[in] VendorGuid Vendor GUID to be found.
835 @param[out] PtrTrack VARIABLE_POINTER_TRACK structure for output,
836 including the range searched and the target position.
837 @param[in] Global Pointer to VARIABLE_GLOBAL structure, including
838 base of volatile variable storage area, base of
839 NV variable storage area, and a lock.
840 @param[in] IgnoreRtCheck Ignore EFI_VARIABLE_RUNTIME_ACCESS attribute
841 check at runtime when searching variable.
843 @retval EFI_INVALID_PARAMETER If VariableName is not an empty string, while
845 @retval EFI_SUCCESS Variable successfully found.
846 @retval EFI_NOT_FOUND Variable not found
851 IN CHAR16
*VariableName
,
852 IN EFI_GUID
*VendorGuid
,
853 OUT VARIABLE_POINTER_TRACK
*PtrTrack
,
854 IN VARIABLE_GLOBAL
*Global
,
855 IN BOOLEAN IgnoreRtCheck
859 VARIABLE_STORE_HEADER
*VariableStoreHeader
[VariableStoreTypeMax
];
860 VARIABLE_STORE_TYPE Type
;
862 if ((VariableName
[0] != 0) && (VendorGuid
== NULL
)) {
863 return EFI_INVALID_PARAMETER
;
867 // 0: Volatile, 1: HOB, 2: Non-Volatile.
868 // The index and attributes mapping must be kept in this order as RuntimeServiceGetNextVariableName
869 // make use of this mapping to implement search algorithm.
871 VariableStoreHeader
[VariableStoreTypeVolatile
] = (VARIABLE_STORE_HEADER
*)(UINTN
)Global
->VolatileVariableBase
;
872 VariableStoreHeader
[VariableStoreTypeHob
] = (VARIABLE_STORE_HEADER
*)(UINTN
)Global
->HobVariableBase
;
873 VariableStoreHeader
[VariableStoreTypeNv
] = mNvVariableCache
;
876 // Find the variable by walk through HOB, volatile and non-volatile variable store.
878 for (Type
= (VARIABLE_STORE_TYPE
)0; Type
< VariableStoreTypeMax
; Type
++) {
879 if (VariableStoreHeader
[Type
] == NULL
) {
883 PtrTrack
->StartPtr
= GetStartPointer (VariableStoreHeader
[Type
]);
884 PtrTrack
->EndPtr
= GetEndPointer (VariableStoreHeader
[Type
]);
885 PtrTrack
->Volatile
= (BOOLEAN
)(Type
== VariableStoreTypeVolatile
);
887 Status
= FindVariableEx (
892 mVariableModuleGlobal
->VariableGlobal
.AuthFormat
894 if (!EFI_ERROR (Status
)) {
899 return EFI_NOT_FOUND
;
903 Get index from supported language codes according to language string.
905 This code is used to get corresponding index in supported language codes. It can handle
906 RFC4646 and ISO639 language tags.
907 In ISO639 language tags, take 3-characters as a delimitation to find matched string and calculate the index.
908 In RFC4646 language tags, take semicolon as a delimitation to find matched string and calculate the index.
911 SupportedLang = "engfraengfra"
913 Iso639Language = TRUE
914 The return value is "0".
916 SupportedLang = "en;fr;en-US;fr-FR"
918 Iso639Language = FALSE
919 The return value is "3".
921 @param SupportedLang Platform supported language codes.
922 @param Lang Configured language.
923 @param Iso639Language A bool value to signify if the handler is operated on ISO639 or RFC4646.
925 @retval The index of language in the language codes.
929 GetIndexFromSupportedLangCodes (
930 IN CHAR8
*SupportedLang
,
932 IN BOOLEAN Iso639Language
937 UINTN LanguageLength
;
939 if (Iso639Language
) {
940 CompareLength
= ISO_639_2_ENTRY_SIZE
;
941 for (Index
= 0; Index
< AsciiStrLen (SupportedLang
); Index
+= CompareLength
) {
942 if (AsciiStrnCmp (Lang
, SupportedLang
+ Index
, CompareLength
) == 0) {
944 // Successfully find the index of Lang string in SupportedLang string.
946 Index
= Index
/ CompareLength
;
955 // Compare RFC4646 language code
958 for (LanguageLength
= 0; Lang
[LanguageLength
] != '\0'; LanguageLength
++) {
961 for (Index
= 0; *SupportedLang
!= '\0'; Index
++, SupportedLang
+= CompareLength
) {
963 // Skip ';' characters in SupportedLang
965 for ( ; *SupportedLang
!= '\0' && *SupportedLang
== ';'; SupportedLang
++) {
969 // Determine the length of the next language code in SupportedLang
971 for (CompareLength
= 0; SupportedLang
[CompareLength
] != '\0' && SupportedLang
[CompareLength
] != ';'; CompareLength
++) {
974 if ((CompareLength
== LanguageLength
) &&
975 (AsciiStrnCmp (Lang
, SupportedLang
, CompareLength
) == 0))
978 // Successfully find the index of Lang string in SupportedLang string.
990 Get language string from supported language codes according to index.
992 This code is used to get corresponding language strings in supported language codes. It can handle
993 RFC4646 and ISO639 language tags.
994 In ISO639 language tags, take 3-characters as a delimitation. Find language string according to the index.
995 In RFC4646 language tags, take semicolon as a delimitation. Find language string according to the index.
998 SupportedLang = "engfraengfra"
1000 Iso639Language = TRUE
1001 The return value is "fra".
1003 SupportedLang = "en;fr;en-US;fr-FR"
1005 Iso639Language = FALSE
1006 The return value is "fr".
1008 @param SupportedLang Platform supported language codes.
1009 @param Index The index in supported language codes.
1010 @param Iso639Language A bool value to signify if the handler is operated on ISO639 or RFC4646.
1012 @retval The language string in the language codes.
1016 GetLangFromSupportedLangCodes (
1017 IN CHAR8
*SupportedLang
,
1019 IN BOOLEAN Iso639Language
1023 UINTN CompareLength
;
1027 Supported
= SupportedLang
;
1028 if (Iso639Language
) {
1030 // According to the index of Lang string in SupportedLang string to get the language.
1031 // This code will be invoked in RUNTIME, therefore there is not a memory allocate/free operation.
1032 // In driver entry, it pre-allocates a runtime attribute memory to accommodate this string.
1034 CompareLength
= ISO_639_2_ENTRY_SIZE
;
1035 mVariableModuleGlobal
->Lang
[CompareLength
] = '\0';
1036 return CopyMem (mVariableModuleGlobal
->Lang
, SupportedLang
+ Index
* CompareLength
, CompareLength
);
1040 // Take semicolon as delimitation, sequentially traverse supported language codes.
1042 for (CompareLength
= 0; *Supported
!= ';' && *Supported
!= '\0'; CompareLength
++) {
1046 if ((*Supported
== '\0') && (SubIndex
!= Index
)) {
1048 // Have completed the traverse, but not find corrsponding string.
1049 // This case is not allowed to happen.
1055 if (SubIndex
== Index
) {
1057 // According to the index of Lang string in SupportedLang string to get the language.
1058 // As this code will be invoked in RUNTIME, therefore there is not memory allocate/free operation.
1059 // In driver entry, it pre-allocates a runtime attribute memory to accommodate this string.
1061 mVariableModuleGlobal
->PlatformLang
[CompareLength
] = '\0';
1062 return CopyMem (mVariableModuleGlobal
->PlatformLang
, Supported
- CompareLength
, CompareLength
);
1068 // Skip ';' characters in Supported
1070 for ( ; *Supported
!= '\0' && *Supported
== ';'; Supported
++) {
1077 Returns a pointer to an allocated buffer that contains the best matching language
1078 from a set of supported languages.
1080 This function supports both ISO 639-2 and RFC 4646 language codes, but language
1081 code types may not be mixed in a single call to this function. This function
1082 supports a variable argument list that allows the caller to pass in a prioritized
1083 list of language codes to test against all the language codes in SupportedLanguages.
1085 If SupportedLanguages is NULL, then ASSERT().
1087 @param[in] SupportedLanguages A pointer to a Null-terminated ASCII string that
1088 contains a set of language codes in the format
1089 specified by Iso639Language.
1090 @param[in] Iso639Language If not zero, then all language codes are assumed to be
1091 in ISO 639-2 format. If zero, then all language
1092 codes are assumed to be in RFC 4646 language format
1093 @param[in] ... A variable argument list that contains pointers to
1094 Null-terminated ASCII strings that contain one or more
1095 language codes in the format specified by Iso639Language.
1096 The first language code from each of these language
1097 code lists is used to determine if it is an exact or
1098 close match to any of the language codes in
1099 SupportedLanguages. Close matches only apply to RFC 4646
1100 language codes, and the matching algorithm from RFC 4647
1101 is used to determine if a close match is present. If
1102 an exact or close match is found, then the matching
1103 language code from SupportedLanguages is returned. If
1104 no matches are found, then the next variable argument
1105 parameter is evaluated. The variable argument list
1106 is terminated by a NULL.
1108 @retval NULL The best matching language could not be found in SupportedLanguages.
1109 @retval NULL There are not enough resources available to return the best matching
1111 @retval Other A pointer to a Null-terminated ASCII string that is the best matching
1112 language in SupportedLanguages.
1117 VariableGetBestLanguage (
1118 IN CONST CHAR8
*SupportedLanguages
,
1119 IN UINTN Iso639Language
,
1125 UINTN CompareLength
;
1126 UINTN LanguageLength
;
1127 CONST CHAR8
*Supported
;
1130 if (SupportedLanguages
== NULL
) {
1134 VA_START (Args
, Iso639Language
);
1135 while ((Language
= VA_ARG (Args
, CHAR8
*)) != NULL
) {
1137 // Default to ISO 639-2 mode
1140 LanguageLength
= MIN (3, AsciiStrLen (Language
));
1143 // If in RFC 4646 mode, then determine the length of the first RFC 4646 language code in Language
1145 if (Iso639Language
== 0) {
1146 for (LanguageLength
= 0; Language
[LanguageLength
] != 0 && Language
[LanguageLength
] != ';'; LanguageLength
++) {
1151 // Trim back the length of Language used until it is empty
1153 while (LanguageLength
> 0) {
1155 // Loop through all language codes in SupportedLanguages
1157 for (Supported
= SupportedLanguages
; *Supported
!= '\0'; Supported
+= CompareLength
) {
1159 // In RFC 4646 mode, then Loop through all language codes in SupportedLanguages
1161 if (Iso639Language
== 0) {
1163 // Skip ';' characters in Supported
1165 for ( ; *Supported
!= '\0' && *Supported
== ';'; Supported
++) {
1169 // Determine the length of the next language code in Supported
1171 for (CompareLength
= 0; Supported
[CompareLength
] != 0 && Supported
[CompareLength
] != ';'; CompareLength
++) {
1175 // If Language is longer than the Supported, then skip to the next language
1177 if (LanguageLength
> CompareLength
) {
1183 // See if the first LanguageLength characters in Supported match Language
1185 if (AsciiStrnCmp (Supported
, Language
, LanguageLength
) == 0) {
1188 Buffer
= (Iso639Language
!= 0) ? mVariableModuleGlobal
->Lang
: mVariableModuleGlobal
->PlatformLang
;
1189 Buffer
[CompareLength
] = '\0';
1190 return CopyMem (Buffer
, Supported
, CompareLength
);
1194 if (Iso639Language
!= 0) {
1196 // If ISO 639 mode, then each language can only be tested once
1201 // If RFC 4646 mode, then trim Language from the right to the next '-' character
1203 for (LanguageLength
--; LanguageLength
> 0 && Language
[LanguageLength
] != '-'; LanguageLength
--) {
1212 // No matches were found
1218 This function is to check if the remaining variable space is enough to set
1219 all Variables from argument list successfully. The purpose of the check
1220 is to keep the consistency of the Variables to be in variable storage.
1222 Note: Variables are assumed to be in same storage.
1223 The set sequence of Variables will be same with the sequence of VariableEntry from argument list,
1224 so follow the argument sequence to check the Variables.
1226 @param[in] Attributes Variable attributes for Variable entries.
1227 @param[in] Marker VA_LIST style variable argument list.
1228 The variable argument list with type VARIABLE_ENTRY_CONSISTENCY *.
1229 A NULL terminates the list. The VariableSize of
1230 VARIABLE_ENTRY_CONSISTENCY is the variable data size as input.
1231 It will be changed to variable total size as output.
1233 @retval TRUE Have enough variable space to set the Variables successfully.
1234 @retval FALSE No enough variable space to set the Variables successfully.
1239 CheckRemainingSpaceForConsistencyInternal (
1240 IN UINT32 Attributes
,
1246 VARIABLE_ENTRY_CONSISTENCY
*VariableEntry
;
1247 UINT64 MaximumVariableStorageSize
;
1248 UINT64 RemainingVariableStorageSize
;
1249 UINT64 MaximumVariableSize
;
1250 UINTN TotalNeededSize
;
1251 UINTN OriginalVarSize
;
1252 VARIABLE_STORE_HEADER
*VariableStoreHeader
;
1253 VARIABLE_POINTER_TRACK VariablePtrTrack
;
1254 VARIABLE_HEADER
*NextVariable
;
1259 // Non-Volatile related.
1261 VariableStoreHeader
= mNvVariableCache
;
1263 Status
= VariableServiceQueryVariableInfoInternal (
1265 &MaximumVariableStorageSize
,
1266 &RemainingVariableStorageSize
,
1267 &MaximumVariableSize
1269 ASSERT_EFI_ERROR (Status
);
1271 TotalNeededSize
= 0;
1272 VA_COPY (Args
, Marker
);
1273 VariableEntry
= VA_ARG (Args
, VARIABLE_ENTRY_CONSISTENCY
*);
1274 while (VariableEntry
!= NULL
) {
1276 // Calculate variable total size.
1278 VarNameSize
= StrSize (VariableEntry
->Name
);
1279 VarNameSize
+= GET_PAD_SIZE (VarNameSize
);
1280 VarDataSize
= VariableEntry
->VariableSize
;
1281 VarDataSize
+= GET_PAD_SIZE (VarDataSize
);
1282 VariableEntry
->VariableSize
= HEADER_ALIGN (
1283 GetVariableHeaderSize (
1284 mVariableModuleGlobal
->VariableGlobal
.AuthFormat
1285 ) + VarNameSize
+ VarDataSize
1288 TotalNeededSize
+= VariableEntry
->VariableSize
;
1289 VariableEntry
= VA_ARG (Args
, VARIABLE_ENTRY_CONSISTENCY
*);
1294 if (RemainingVariableStorageSize
>= TotalNeededSize
) {
1296 // Already have enough space.
1299 } else if (AtRuntime ()) {
1301 // At runtime, no reclaim.
1302 // The original variable space of Variables can't be reused.
1307 VA_COPY (Args
, Marker
);
1308 VariableEntry
= VA_ARG (Args
, VARIABLE_ENTRY_CONSISTENCY
*);
1309 while (VariableEntry
!= NULL
) {
1311 // Check if Variable[Index] has been present and get its size.
1313 OriginalVarSize
= 0;
1314 VariablePtrTrack
.StartPtr
= GetStartPointer (VariableStoreHeader
);
1315 VariablePtrTrack
.EndPtr
= GetEndPointer (VariableStoreHeader
);
1316 Status
= FindVariableEx (
1317 VariableEntry
->Name
,
1318 VariableEntry
->Guid
,
1321 mVariableModuleGlobal
->VariableGlobal
.AuthFormat
1323 if (!EFI_ERROR (Status
)) {
1325 // Get size of Variable[Index].
1327 NextVariable
= GetNextVariablePtr (VariablePtrTrack
.CurrPtr
, mVariableModuleGlobal
->VariableGlobal
.AuthFormat
);
1328 OriginalVarSize
= (UINTN
)NextVariable
- (UINTN
)VariablePtrTrack
.CurrPtr
;
1330 // Add the original size of Variable[Index] to remaining variable storage size.
1332 RemainingVariableStorageSize
+= OriginalVarSize
;
1335 if (VariableEntry
->VariableSize
> RemainingVariableStorageSize
) {
1337 // No enough space for Variable[Index].
1344 // Sub the (new) size of Variable[Index] from remaining variable storage size.
1346 RemainingVariableStorageSize
-= VariableEntry
->VariableSize
;
1347 VariableEntry
= VA_ARG (Args
, VARIABLE_ENTRY_CONSISTENCY
*);
1356 This function is to check if the remaining variable space is enough to set
1357 all Variables from argument list successfully. The purpose of the check
1358 is to keep the consistency of the Variables to be in variable storage.
1360 Note: Variables are assumed to be in same storage.
1361 The set sequence of Variables will be same with the sequence of VariableEntry from argument list,
1362 so follow the argument sequence to check the Variables.
1364 @param[in] Attributes Variable attributes for Variable entries.
1365 @param ... The variable argument list with type VARIABLE_ENTRY_CONSISTENCY *.
1366 A NULL terminates the list. The VariableSize of
1367 VARIABLE_ENTRY_CONSISTENCY is the variable data size as input.
1368 It will be changed to variable total size as output.
1370 @retval TRUE Have enough variable space to set the Variables successfully.
1371 @retval FALSE No enough variable space to set the Variables successfully.
1376 CheckRemainingSpaceForConsistency (
1377 IN UINT32 Attributes
,
1384 VA_START (Marker
, Attributes
);
1386 Return
= CheckRemainingSpaceForConsistencyInternal (Attributes
, Marker
);
1394 Hook the operations in PlatformLangCodes, LangCodes, PlatformLang and Lang.
1396 When setting Lang/LangCodes, simultaneously update PlatformLang/PlatformLangCodes.
1398 According to UEFI spec, PlatformLangCodes/LangCodes are only set once in firmware initialization,
1399 and are read-only. Therefore, in variable driver, only store the original value for other use.
1401 @param[in] VariableName Name of variable.
1403 @param[in] Data Variable data.
1405 @param[in] DataSize Size of data. 0 means delete.
1407 @retval EFI_SUCCESS The update operation is successful or ignored.
1408 @retval EFI_WRITE_PROTECTED Update PlatformLangCodes/LangCodes at runtime.
1409 @retval EFI_OUT_OF_RESOURCES No enough variable space to do the update operation.
1410 @retval Others Other errors happened during the update operation.
1414 AutoUpdateLangVariable (
1415 IN CHAR16
*VariableName
,
1421 CHAR8
*BestPlatformLang
;
1425 VARIABLE_POINTER_TRACK Variable
;
1426 BOOLEAN SetLanguageCodes
;
1427 VARIABLE_ENTRY_CONSISTENCY VariableEntry
[2];
1430 // Don't do updates for delete operation
1432 if (DataSize
== 0) {
1436 SetLanguageCodes
= FALSE
;
1438 if (StrCmp (VariableName
, EFI_PLATFORM_LANG_CODES_VARIABLE_NAME
) == 0) {
1440 // PlatformLangCodes is a volatile variable, so it can not be updated at runtime.
1443 return EFI_WRITE_PROTECTED
;
1446 SetLanguageCodes
= TRUE
;
1449 // According to UEFI spec, PlatformLangCodes is only set once in firmware initialization, and is read-only
1450 // Therefore, in variable driver, only store the original value for other use.
1452 if (mVariableModuleGlobal
->PlatformLangCodes
!= NULL
) {
1453 FreePool (mVariableModuleGlobal
->PlatformLangCodes
);
1456 mVariableModuleGlobal
->PlatformLangCodes
= AllocateRuntimeCopyPool (DataSize
, Data
);
1457 ASSERT (mVariableModuleGlobal
->PlatformLangCodes
!= NULL
);
1460 // PlatformLang holds a single language from PlatformLangCodes,
1461 // so the size of PlatformLangCodes is enough for the PlatformLang.
1463 if (mVariableModuleGlobal
->PlatformLang
!= NULL
) {
1464 FreePool (mVariableModuleGlobal
->PlatformLang
);
1467 mVariableModuleGlobal
->PlatformLang
= AllocateRuntimePool (DataSize
);
1468 ASSERT (mVariableModuleGlobal
->PlatformLang
!= NULL
);
1469 } else if (StrCmp (VariableName
, EFI_LANG_CODES_VARIABLE_NAME
) == 0) {
1471 // LangCodes is a volatile variable, so it can not be updated at runtime.
1474 return EFI_WRITE_PROTECTED
;
1477 SetLanguageCodes
= TRUE
;
1480 // According to UEFI spec, LangCodes is only set once in firmware initialization, and is read-only
1481 // Therefore, in variable driver, only store the original value for other use.
1483 if (mVariableModuleGlobal
->LangCodes
!= NULL
) {
1484 FreePool (mVariableModuleGlobal
->LangCodes
);
1487 mVariableModuleGlobal
->LangCodes
= AllocateRuntimeCopyPool (DataSize
, Data
);
1488 ASSERT (mVariableModuleGlobal
->LangCodes
!= NULL
);
1491 if ( SetLanguageCodes
1492 && (mVariableModuleGlobal
->PlatformLangCodes
!= NULL
)
1493 && (mVariableModuleGlobal
->LangCodes
!= NULL
))
1496 // Update Lang if PlatformLang is already set
1497 // Update PlatformLang if Lang is already set
1499 Status
= FindVariable (EFI_PLATFORM_LANG_VARIABLE_NAME
, &gEfiGlobalVariableGuid
, &Variable
, &mVariableModuleGlobal
->VariableGlobal
, FALSE
);
1500 if (!EFI_ERROR (Status
)) {
1504 VariableName
= EFI_PLATFORM_LANG_VARIABLE_NAME
;
1505 Data
= GetVariableDataPtr (Variable
.CurrPtr
, mVariableModuleGlobal
->VariableGlobal
.AuthFormat
);
1506 DataSize
= DataSizeOfVariable (Variable
.CurrPtr
, mVariableModuleGlobal
->VariableGlobal
.AuthFormat
);
1508 Status
= FindVariable (EFI_LANG_VARIABLE_NAME
, &gEfiGlobalVariableGuid
, &Variable
, &mVariableModuleGlobal
->VariableGlobal
, FALSE
);
1509 if (!EFI_ERROR (Status
)) {
1511 // Update PlatformLang
1513 VariableName
= EFI_LANG_VARIABLE_NAME
;
1514 Data
= GetVariableDataPtr (Variable
.CurrPtr
, mVariableModuleGlobal
->VariableGlobal
.AuthFormat
);
1515 DataSize
= DataSizeOfVariable (Variable
.CurrPtr
, mVariableModuleGlobal
->VariableGlobal
.AuthFormat
);
1518 // Neither PlatformLang nor Lang is set, directly return
1525 Status
= EFI_SUCCESS
;
1528 // According to UEFI spec, "Lang" and "PlatformLang" is NV|BS|RT attributions.
1530 Attributes
= EFI_VARIABLE_NON_VOLATILE
| EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_RUNTIME_ACCESS
;
1532 if (StrCmp (VariableName
, EFI_PLATFORM_LANG_VARIABLE_NAME
) == 0) {
1534 // Update Lang when PlatformLangCodes/LangCodes were set.
1536 if ((mVariableModuleGlobal
->PlatformLangCodes
!= NULL
) && (mVariableModuleGlobal
->LangCodes
!= NULL
)) {
1538 // When setting PlatformLang, firstly get most matched language string from supported language codes.
1540 BestPlatformLang
= VariableGetBestLanguage (mVariableModuleGlobal
->PlatformLangCodes
, FALSE
, Data
, NULL
);
1541 if (BestPlatformLang
!= NULL
) {
1543 // Get the corresponding index in language codes.
1545 Index
= GetIndexFromSupportedLangCodes (mVariableModuleGlobal
->PlatformLangCodes
, BestPlatformLang
, FALSE
);
1548 // Get the corresponding ISO639 language tag according to RFC4646 language tag.
1550 BestLang
= GetLangFromSupportedLangCodes (mVariableModuleGlobal
->LangCodes
, Index
, TRUE
);
1553 // Check the variable space for both Lang and PlatformLang variable.
1555 VariableEntry
[0].VariableSize
= ISO_639_2_ENTRY_SIZE
+ 1;
1556 VariableEntry
[0].Guid
= &gEfiGlobalVariableGuid
;
1557 VariableEntry
[0].Name
= EFI_LANG_VARIABLE_NAME
;
1559 VariableEntry
[1].VariableSize
= AsciiStrSize (BestPlatformLang
);
1560 VariableEntry
[1].Guid
= &gEfiGlobalVariableGuid
;
1561 VariableEntry
[1].Name
= EFI_PLATFORM_LANG_VARIABLE_NAME
;
1562 if (!CheckRemainingSpaceForConsistency (VARIABLE_ATTRIBUTE_NV_BS_RT
, &VariableEntry
[0], &VariableEntry
[1], NULL
)) {
1564 // No enough variable space to set both Lang and PlatformLang successfully.
1566 Status
= EFI_OUT_OF_RESOURCES
;
1569 // Successfully convert PlatformLang to Lang, and set the BestLang value into Lang variable simultaneously.
1571 FindVariable (EFI_LANG_VARIABLE_NAME
, &gEfiGlobalVariableGuid
, &Variable
, &mVariableModuleGlobal
->VariableGlobal
, FALSE
);
1573 Status
= UpdateVariable (
1574 EFI_LANG_VARIABLE_NAME
,
1575 &gEfiGlobalVariableGuid
,
1577 ISO_639_2_ENTRY_SIZE
+ 1,
1586 DEBUG ((DEBUG_INFO
, "Variable Driver Auto Update PlatformLang, PlatformLang:%a, Lang:%a Status: %r\n", BestPlatformLang
, BestLang
, Status
));
1589 } else if (StrCmp (VariableName
, EFI_LANG_VARIABLE_NAME
) == 0) {
1591 // Update PlatformLang when PlatformLangCodes/LangCodes were set.
1593 if ((mVariableModuleGlobal
->PlatformLangCodes
!= NULL
) && (mVariableModuleGlobal
->LangCodes
!= NULL
)) {
1595 // When setting Lang, firstly get most matched language string from supported language codes.
1597 BestLang
= VariableGetBestLanguage (mVariableModuleGlobal
->LangCodes
, TRUE
, Data
, NULL
);
1598 if (BestLang
!= NULL
) {
1600 // Get the corresponding index in language codes.
1602 Index
= GetIndexFromSupportedLangCodes (mVariableModuleGlobal
->LangCodes
, BestLang
, TRUE
);
1605 // Get the corresponding RFC4646 language tag according to ISO639 language tag.
1607 BestPlatformLang
= GetLangFromSupportedLangCodes (mVariableModuleGlobal
->PlatformLangCodes
, Index
, FALSE
);
1610 // Check the variable space for both PlatformLang and Lang variable.
1612 VariableEntry
[0].VariableSize
= AsciiStrSize (BestPlatformLang
);
1613 VariableEntry
[0].Guid
= &gEfiGlobalVariableGuid
;
1614 VariableEntry
[0].Name
= EFI_PLATFORM_LANG_VARIABLE_NAME
;
1616 VariableEntry
[1].VariableSize
= ISO_639_2_ENTRY_SIZE
+ 1;
1617 VariableEntry
[1].Guid
= &gEfiGlobalVariableGuid
;
1618 VariableEntry
[1].Name
= EFI_LANG_VARIABLE_NAME
;
1619 if (!CheckRemainingSpaceForConsistency (VARIABLE_ATTRIBUTE_NV_BS_RT
, &VariableEntry
[0], &VariableEntry
[1], NULL
)) {
1621 // No enough variable space to set both PlatformLang and Lang successfully.
1623 Status
= EFI_OUT_OF_RESOURCES
;
1626 // Successfully convert Lang to PlatformLang, and set the BestPlatformLang value into PlatformLang variable simultaneously.
1628 FindVariable (EFI_PLATFORM_LANG_VARIABLE_NAME
, &gEfiGlobalVariableGuid
, &Variable
, &mVariableModuleGlobal
->VariableGlobal
, FALSE
);
1630 Status
= UpdateVariable (
1631 EFI_PLATFORM_LANG_VARIABLE_NAME
,
1632 &gEfiGlobalVariableGuid
,
1634 AsciiStrSize (BestPlatformLang
),
1643 DEBUG ((DEBUG_INFO
, "Variable Driver Auto Update Lang, Lang:%a, PlatformLang:%a Status: %r\n", BestLang
, BestPlatformLang
, Status
));
1648 if (SetLanguageCodes
) {
1650 // Continue to set PlatformLangCodes or LangCodes.
1659 Update the variable region with Variable information. If EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS is set,
1660 index of associated public key is needed.
1662 @param[in] VariableName Name of variable.
1663 @param[in] VendorGuid Guid of variable.
1664 @param[in] Data Variable data.
1665 @param[in] DataSize Size of data. 0 means delete.
1666 @param[in] Attributes Attributes of the variable.
1667 @param[in] KeyIndex Index of associated public key.
1668 @param[in] MonotonicCount Value of associated monotonic count.
1669 @param[in, out] CacheVariable The variable information which is used to keep track of variable usage.
1670 @param[in] TimeStamp Value of associated TimeStamp.
1672 @retval EFI_SUCCESS The update operation is success.
1673 @retval EFI_OUT_OF_RESOURCES Variable region is full, can not write other data into this region.
1678 IN CHAR16
*VariableName
,
1679 IN EFI_GUID
*VendorGuid
,
1682 IN UINT32 Attributes OPTIONAL
,
1683 IN UINT32 KeyIndex OPTIONAL
,
1684 IN UINT64 MonotonicCount OPTIONAL
,
1685 IN OUT VARIABLE_POINTER_TRACK
*CacheVariable
,
1686 IN EFI_TIME
*TimeStamp OPTIONAL
1690 VARIABLE_HEADER
*NextVariable
;
1693 UINTN VarNameOffset
;
1694 UINTN VarDataOffset
;
1698 EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*Fvb
;
1700 VARIABLE_POINTER_TRACK
*Variable
;
1701 VARIABLE_POINTER_TRACK NvVariable
;
1702 VARIABLE_STORE_HEADER
*VariableStoreHeader
;
1703 VARIABLE_RUNTIME_CACHE
*VolatileCacheInstance
;
1704 UINT8
*BufferForMerge
;
1705 UINTN MergedBufSize
;
1708 BOOLEAN IsCommonVariable
;
1709 BOOLEAN IsCommonUserVariable
;
1710 AUTHENTICATED_VARIABLE_HEADER
*AuthVariable
;
1713 if ((mVariableModuleGlobal
->FvbInstance
== NULL
) && !mVariableModuleGlobal
->VariableGlobal
.EmuNvMode
) {
1715 // The FVB protocol is not ready, so the EFI_VARIABLE_WRITE_ARCH_PROTOCOL is not installed.
1717 if ((Attributes
& EFI_VARIABLE_NON_VOLATILE
) != 0) {
1719 // Trying to update NV variable prior to the installation of EFI_VARIABLE_WRITE_ARCH_PROTOCOL
1721 DEBUG ((DEBUG_ERROR
, "Update NV variable before EFI_VARIABLE_WRITE_ARCH_PROTOCOL ready - %r\n", EFI_NOT_AVAILABLE_YET
));
1722 return EFI_NOT_AVAILABLE_YET
;
1723 } else if ((Attributes
& VARIABLE_ATTRIBUTE_AT_AW
) != 0) {
1725 // Trying to update volatile authenticated variable prior to the installation of EFI_VARIABLE_WRITE_ARCH_PROTOCOL
1726 // The authenticated variable perhaps is not initialized, just return here.
1728 DEBUG ((DEBUG_ERROR
, "Update AUTH variable before EFI_VARIABLE_WRITE_ARCH_PROTOCOL ready - %r\n", EFI_NOT_AVAILABLE_YET
));
1729 return EFI_NOT_AVAILABLE_YET
;
1733 AuthFormat
= mVariableModuleGlobal
->VariableGlobal
.AuthFormat
;
1736 // Check if CacheVariable points to the variable in variable HOB.
1737 // If yes, let CacheVariable points to the variable in NV variable cache.
1739 if ((CacheVariable
->CurrPtr
!= NULL
) &&
1740 (mVariableModuleGlobal
->VariableGlobal
.HobVariableBase
!= 0) &&
1741 (CacheVariable
->StartPtr
== GetStartPointer ((VARIABLE_STORE_HEADER
*)(UINTN
)mVariableModuleGlobal
->VariableGlobal
.HobVariableBase
))
1744 CacheVariable
->StartPtr
= GetStartPointer (mNvVariableCache
);
1745 CacheVariable
->EndPtr
= GetEndPointer (mNvVariableCache
);
1746 CacheVariable
->Volatile
= FALSE
;
1747 Status
= FindVariableEx (VariableName
, VendorGuid
, FALSE
, CacheVariable
, AuthFormat
);
1748 if ((CacheVariable
->CurrPtr
== NULL
) || EFI_ERROR (Status
)) {
1750 // There is no matched variable in NV variable cache.
1752 if ((((Attributes
& EFI_VARIABLE_APPEND_WRITE
) == 0) && (DataSize
== 0)) || (Attributes
== 0)) {
1754 // It is to delete variable,
1755 // go to delete this variable in variable HOB and
1756 // try to flush other variables from HOB to flash.
1758 UpdateVariableInfo (VariableName
, VendorGuid
, FALSE
, FALSE
, FALSE
, TRUE
, FALSE
, &gVariableInfo
);
1759 FlushHobVariableToFlash (VariableName
, VendorGuid
);
1765 if ((CacheVariable
->CurrPtr
== NULL
) || CacheVariable
->Volatile
) {
1766 Variable
= CacheVariable
;
1769 // Update/Delete existing NV variable.
1770 // CacheVariable points to the variable in the memory copy of Flash area
1771 // Now let Variable points to the same variable in Flash area.
1773 VariableStoreHeader
= (VARIABLE_STORE_HEADER
*)((UINTN
)mVariableModuleGlobal
->VariableGlobal
.NonVolatileVariableBase
);
1774 Variable
= &NvVariable
;
1775 Variable
->StartPtr
= GetStartPointer (VariableStoreHeader
);
1776 Variable
->EndPtr
= (VARIABLE_HEADER
*)((UINTN
)Variable
->StartPtr
+ ((UINTN
)CacheVariable
->EndPtr
- (UINTN
)CacheVariable
->StartPtr
));
1778 Variable
->CurrPtr
= (VARIABLE_HEADER
*)((UINTN
)Variable
->StartPtr
+ ((UINTN
)CacheVariable
->CurrPtr
- (UINTN
)CacheVariable
->StartPtr
));
1779 if (CacheVariable
->InDeletedTransitionPtr
!= NULL
) {
1780 Variable
->InDeletedTransitionPtr
= (VARIABLE_HEADER
*)((UINTN
)Variable
->StartPtr
+ ((UINTN
)CacheVariable
->InDeletedTransitionPtr
- (UINTN
)CacheVariable
->StartPtr
));
1782 Variable
->InDeletedTransitionPtr
= NULL
;
1785 Variable
->Volatile
= FALSE
;
1788 Fvb
= mVariableModuleGlobal
->FvbInstance
;
1791 // Tricky part: Use scratch data area at the end of volatile variable store
1792 // as a temporary storage.
1794 NextVariable
= GetEndPointer ((VARIABLE_STORE_HEADER
*)((UINTN
)mVariableModuleGlobal
->VariableGlobal
.VolatileVariableBase
));
1795 ScratchSize
= mVariableModuleGlobal
->ScratchBufferSize
;
1796 SetMem (NextVariable
, ScratchSize
, 0xff);
1799 if (Variable
->CurrPtr
!= NULL
) {
1801 // Update/Delete existing variable.
1805 // If AtRuntime and the variable is Volatile and Runtime Access,
1806 // the volatile is ReadOnly, and SetVariable should be aborted and
1807 // return EFI_WRITE_PROTECTED.
1809 if (Variable
->Volatile
) {
1810 Status
= EFI_WRITE_PROTECTED
;
1815 // Only variable that have NV attributes can be updated/deleted in Runtime.
1817 if ((CacheVariable
->CurrPtr
->Attributes
& EFI_VARIABLE_NON_VOLATILE
) == 0) {
1818 Status
= EFI_INVALID_PARAMETER
;
1823 // Only variable that have RT attributes can be updated/deleted in Runtime.
1825 if ((CacheVariable
->CurrPtr
->Attributes
& EFI_VARIABLE_RUNTIME_ACCESS
) == 0) {
1826 Status
= EFI_INVALID_PARAMETER
;
1832 // Setting a data variable with no access, or zero DataSize attributes
1833 // causes it to be deleted.
1834 // When the EFI_VARIABLE_APPEND_WRITE attribute is set, DataSize of zero will
1835 // not delete the variable.
1837 if ((((Attributes
& EFI_VARIABLE_APPEND_WRITE
) == 0) && (DataSize
== 0)) || ((Attributes
& (EFI_VARIABLE_RUNTIME_ACCESS
| EFI_VARIABLE_BOOTSERVICE_ACCESS
)) == 0)) {
1838 if (Variable
->InDeletedTransitionPtr
!= NULL
) {
1840 // Both ADDED and IN_DELETED_TRANSITION variable are present,
1841 // set IN_DELETED_TRANSITION one to DELETED state first.
1843 ASSERT (CacheVariable
->InDeletedTransitionPtr
!= NULL
);
1844 State
= CacheVariable
->InDeletedTransitionPtr
->State
;
1845 State
&= VAR_DELETED
;
1846 Status
= UpdateVariableStore (
1847 &mVariableModuleGlobal
->VariableGlobal
,
1851 (UINTN
)&Variable
->InDeletedTransitionPtr
->State
,
1855 if (!EFI_ERROR (Status
)) {
1856 if (!Variable
->Volatile
) {
1857 CacheVariable
->InDeletedTransitionPtr
->State
= State
;
1864 State
= CacheVariable
->CurrPtr
->State
;
1865 State
&= VAR_DELETED
;
1867 Status
= UpdateVariableStore (
1868 &mVariableModuleGlobal
->VariableGlobal
,
1872 (UINTN
)&Variable
->CurrPtr
->State
,
1876 if (!EFI_ERROR (Status
)) {
1877 UpdateVariableInfo (VariableName
, VendorGuid
, Variable
->Volatile
, FALSE
, FALSE
, TRUE
, FALSE
, &gVariableInfo
);
1878 if (!Variable
->Volatile
) {
1879 CacheVariable
->CurrPtr
->State
= State
;
1880 FlushHobVariableToFlash (VariableName
, VendorGuid
);
1888 // If the variable is marked valid, and the same data has been passed in,
1889 // then return to the caller immediately.
1891 if ((DataSizeOfVariable (CacheVariable
->CurrPtr
, AuthFormat
) == DataSize
) &&
1892 (CompareMem (Data
, GetVariableDataPtr (CacheVariable
->CurrPtr
, AuthFormat
), DataSize
) == 0) &&
1893 ((Attributes
& EFI_VARIABLE_APPEND_WRITE
) == 0) &&
1894 (TimeStamp
== NULL
))
1897 // Variable content unchanged and no need to update timestamp, just return.
1899 UpdateVariableInfo (VariableName
, VendorGuid
, Variable
->Volatile
, FALSE
, TRUE
, FALSE
, FALSE
, &gVariableInfo
);
1900 Status
= EFI_SUCCESS
;
1902 } else if ((CacheVariable
->CurrPtr
->State
== VAR_ADDED
) ||
1903 (CacheVariable
->CurrPtr
->State
== (VAR_ADDED
& VAR_IN_DELETED_TRANSITION
)))
1906 // EFI_VARIABLE_APPEND_WRITE attribute only effects for existing variable.
1908 if ((Attributes
& EFI_VARIABLE_APPEND_WRITE
) != 0) {
1910 // NOTE: From 0 to DataOffset of NextVariable is reserved for Variable Header and Name.
1911 // From DataOffset of NextVariable is to save the existing variable data.
1913 DataOffset
= GetVariableDataOffset (CacheVariable
->CurrPtr
, AuthFormat
);
1914 BufferForMerge
= (UINT8
*)((UINTN
)NextVariable
+ DataOffset
);
1917 (UINT8
*)((UINTN
)CacheVariable
->CurrPtr
+ DataOffset
),
1918 DataSizeOfVariable (CacheVariable
->CurrPtr
, AuthFormat
)
1922 // Set Max Auth/Non-Volatile/Volatile Variable Data Size as default MaxDataSize.
1924 if ((Attributes
& VARIABLE_ATTRIBUTE_AT_AW
) != 0) {
1925 MaxDataSize
= mVariableModuleGlobal
->MaxAuthVariableSize
- DataOffset
;
1926 } else if ((Attributes
& EFI_VARIABLE_NON_VOLATILE
) != 0) {
1927 MaxDataSize
= mVariableModuleGlobal
->MaxVariableSize
- DataOffset
;
1929 MaxDataSize
= mVariableModuleGlobal
->MaxVolatileVariableSize
- DataOffset
;
1933 // Append the new data to the end of existing data.
1934 // Max Harware error record variable data size is different from common/auth variable.
1936 if ((Attributes
& EFI_VARIABLE_HARDWARE_ERROR_RECORD
) == EFI_VARIABLE_HARDWARE_ERROR_RECORD
) {
1937 MaxDataSize
= PcdGet32 (PcdMaxHardwareErrorVariableSize
) - DataOffset
;
1940 if (DataSizeOfVariable (CacheVariable
->CurrPtr
, AuthFormat
) + DataSize
> MaxDataSize
) {
1942 // Existing data size + new data size exceed maximum variable size limitation.
1944 Status
= EFI_INVALID_PARAMETER
;
1950 (UINTN
)BufferForMerge
+ DataSizeOfVariable (CacheVariable
->CurrPtr
, AuthFormat
)
1955 MergedBufSize
= DataSizeOfVariable (CacheVariable
->CurrPtr
, AuthFormat
) +
1959 // BufferForMerge(from DataOffset of NextVariable) has included the merged existing and new data.
1961 Data
= BufferForMerge
;
1962 DataSize
= MergedBufSize
;
1967 // Mark the old variable as in delete transition.
1969 State
= CacheVariable
->CurrPtr
->State
;
1970 State
&= VAR_IN_DELETED_TRANSITION
;
1972 Status
= UpdateVariableStore (
1973 &mVariableModuleGlobal
->VariableGlobal
,
1977 (UINTN
)&Variable
->CurrPtr
->State
,
1981 if (EFI_ERROR (Status
)) {
1985 if (!Variable
->Volatile
) {
1986 CacheVariable
->CurrPtr
->State
= State
;
1991 // Not found existing variable. Create a new variable.
1994 if ((DataSize
== 0) && ((Attributes
& EFI_VARIABLE_APPEND_WRITE
) != 0)) {
1995 Status
= EFI_SUCCESS
;
2000 // Make sure we are trying to create a new variable.
2001 // Setting a data variable with zero DataSize or no access attributes means to delete it.
2003 if ((DataSize
== 0) || ((Attributes
& (EFI_VARIABLE_RUNTIME_ACCESS
| EFI_VARIABLE_BOOTSERVICE_ACCESS
)) == 0)) {
2004 Status
= EFI_NOT_FOUND
;
2009 // Only variable have NV|RT attribute can be created in Runtime.
2012 (((Attributes
& EFI_VARIABLE_RUNTIME_ACCESS
) == 0) || ((Attributes
& EFI_VARIABLE_NON_VOLATILE
) == 0)))
2014 Status
= EFI_INVALID_PARAMETER
;
2020 // Function part - create a new variable and copy the data.
2021 // Both update a variable and create a variable will come here.
2023 NextVariable
->StartId
= VARIABLE_DATA
;
2025 // NextVariable->State = VAR_ADDED;
2027 NextVariable
->Reserved
= 0;
2028 if (mVariableModuleGlobal
->VariableGlobal
.AuthFormat
) {
2029 AuthVariable
= (AUTHENTICATED_VARIABLE_HEADER
*)NextVariable
;
2030 AuthVariable
->PubKeyIndex
= KeyIndex
;
2031 AuthVariable
->MonotonicCount
= MonotonicCount
;
2032 ZeroMem (&AuthVariable
->TimeStamp
, sizeof (EFI_TIME
));
2034 if (((Attributes
& EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS
) != 0) &&
2035 (TimeStamp
!= NULL
))
2037 if ((Attributes
& EFI_VARIABLE_APPEND_WRITE
) == 0) {
2038 CopyMem (&AuthVariable
->TimeStamp
, TimeStamp
, sizeof (EFI_TIME
));
2041 // In the case when the EFI_VARIABLE_APPEND_WRITE attribute is set, only
2042 // when the new TimeStamp value is later than the current timestamp associated
2043 // with the variable, we need associate the new timestamp with the updated value.
2045 if (Variable
->CurrPtr
!= NULL
) {
2046 if (VariableCompareTimeStampInternal (&(((AUTHENTICATED_VARIABLE_HEADER
*)CacheVariable
->CurrPtr
)->TimeStamp
), TimeStamp
)) {
2047 CopyMem (&AuthVariable
->TimeStamp
, TimeStamp
, sizeof (EFI_TIME
));
2049 CopyMem (&AuthVariable
->TimeStamp
, &(((AUTHENTICATED_VARIABLE_HEADER
*)CacheVariable
->CurrPtr
)->TimeStamp
), sizeof (EFI_TIME
));
2057 // The EFI_VARIABLE_APPEND_WRITE attribute will never be set in the returned
2058 // Attributes bitmask parameter of a GetVariable() call.
2060 NextVariable
->Attributes
= Attributes
& (~EFI_VARIABLE_APPEND_WRITE
);
2062 VarNameOffset
= GetVariableHeaderSize (AuthFormat
);
2063 VarNameSize
= StrSize (VariableName
);
2065 (UINT8
*)((UINTN
)NextVariable
+ VarNameOffset
),
2069 VarDataOffset
= VarNameOffset
+ VarNameSize
+ GET_PAD_SIZE (VarNameSize
);
2072 // If DataReady is TRUE, it means the variable data has been saved into
2073 // NextVariable during EFI_VARIABLE_APPEND_WRITE operation preparation.
2077 (UINT8
*)((UINTN
)NextVariable
+ VarDataOffset
),
2084 GetVendorGuidPtr (NextVariable
, AuthFormat
),
2089 // There will be pad bytes after Data, the NextVariable->NameSize and
2090 // NextVariable->DataSize should not include pad size so that variable
2091 // service can get actual size in GetVariable.
2093 SetNameSizeOfVariable (NextVariable
, VarNameSize
, AuthFormat
);
2094 SetDataSizeOfVariable (NextVariable
, DataSize
, AuthFormat
);
2097 // The actual size of the variable that stores in storage should
2098 // include pad size.
2100 VarSize
= VarDataOffset
+ DataSize
+ GET_PAD_SIZE (DataSize
);
2101 if ((Attributes
& EFI_VARIABLE_NON_VOLATILE
) != 0) {
2103 // Create a nonvolatile variable.
2107 IsCommonVariable
= FALSE
;
2108 IsCommonUserVariable
= FALSE
;
2109 if ((Attributes
& EFI_VARIABLE_HARDWARE_ERROR_RECORD
) == 0) {
2110 IsCommonVariable
= TRUE
;
2111 IsCommonUserVariable
= IsUserVariable (NextVariable
);
2114 if ( ( ((Attributes
& EFI_VARIABLE_HARDWARE_ERROR_RECORD
) != 0)
2115 && ((VarSize
+ mVariableModuleGlobal
->HwErrVariableTotalSize
) > PcdGet32 (PcdHwErrStorageSize
)))
2116 || (IsCommonVariable
&& ((VarSize
+ mVariableModuleGlobal
->CommonVariableTotalSize
) > mVariableModuleGlobal
->CommonVariableSpace
))
2117 || (IsCommonVariable
&& AtRuntime () && ((VarSize
+ mVariableModuleGlobal
->CommonVariableTotalSize
) > mVariableModuleGlobal
->CommonRuntimeVariableSpace
))
2118 || (IsCommonUserVariable
&& ((VarSize
+ mVariableModuleGlobal
->CommonUserVariableTotalSize
) > mVariableModuleGlobal
->CommonMaxUserVariableSpace
)))
2121 if (IsCommonUserVariable
&& ((VarSize
+ mVariableModuleGlobal
->CommonUserVariableTotalSize
) > mVariableModuleGlobal
->CommonMaxUserVariableSpace
)) {
2122 RecordVarErrorFlag (VAR_ERROR_FLAG_USER_ERROR
, VariableName
, VendorGuid
, Attributes
, VarSize
);
2125 if (IsCommonVariable
&& ((VarSize
+ mVariableModuleGlobal
->CommonVariableTotalSize
) > mVariableModuleGlobal
->CommonRuntimeVariableSpace
)) {
2126 RecordVarErrorFlag (VAR_ERROR_FLAG_SYSTEM_ERROR
, VariableName
, VendorGuid
, Attributes
, VarSize
);
2129 Status
= EFI_OUT_OF_RESOURCES
;
2134 // Perform garbage collection & reclaim operation, and integrate the new variable at the same time.
2137 mVariableModuleGlobal
->VariableGlobal
.NonVolatileVariableBase
,
2138 &mVariableModuleGlobal
->NonVolatileLastVariableOffset
,
2142 HEADER_ALIGN (VarSize
)
2144 if (!EFI_ERROR (Status
)) {
2146 // The new variable has been integrated successfully during reclaiming.
2148 if (Variable
->CurrPtr
!= NULL
) {
2149 CacheVariable
->CurrPtr
= (VARIABLE_HEADER
*)((UINTN
)CacheVariable
->StartPtr
+ ((UINTN
)Variable
->CurrPtr
- (UINTN
)Variable
->StartPtr
));
2150 CacheVariable
->InDeletedTransitionPtr
= NULL
;
2153 UpdateVariableInfo (VariableName
, VendorGuid
, FALSE
, FALSE
, TRUE
, FALSE
, FALSE
, &gVariableInfo
);
2154 FlushHobVariableToFlash (VariableName
, VendorGuid
);
2156 if (IsCommonUserVariable
&& ((VarSize
+ mVariableModuleGlobal
->CommonUserVariableTotalSize
) > mVariableModuleGlobal
->CommonMaxUserVariableSpace
)) {
2157 RecordVarErrorFlag (VAR_ERROR_FLAG_USER_ERROR
, VariableName
, VendorGuid
, Attributes
, VarSize
);
2160 if (IsCommonVariable
&& ((VarSize
+ mVariableModuleGlobal
->CommonVariableTotalSize
) > mVariableModuleGlobal
->CommonVariableSpace
)) {
2161 RecordVarErrorFlag (VAR_ERROR_FLAG_SYSTEM_ERROR
, VariableName
, VendorGuid
, Attributes
, VarSize
);
2168 if (!mVariableModuleGlobal
->VariableGlobal
.EmuNvMode
) {
2171 // 1. Write variable header
2172 // 2. Set variable state to header valid
2173 // 3. Write variable data
2174 // 4. Set variable state to valid
2179 Status
= UpdateVariableStore (
2180 &mVariableModuleGlobal
->VariableGlobal
,
2184 mVariableModuleGlobal
->NonVolatileLastVariableOffset
,
2185 (UINT32
)GetVariableHeaderSize (AuthFormat
),
2186 (UINT8
*)NextVariable
2189 if (EFI_ERROR (Status
)) {
2196 NextVariable
->State
= VAR_HEADER_VALID_ONLY
;
2197 Status
= UpdateVariableStore (
2198 &mVariableModuleGlobal
->VariableGlobal
,
2202 mVariableModuleGlobal
->NonVolatileLastVariableOffset
+ OFFSET_OF (VARIABLE_HEADER
, State
),
2204 &NextVariable
->State
2207 if (EFI_ERROR (Status
)) {
2214 Status
= UpdateVariableStore (
2215 &mVariableModuleGlobal
->VariableGlobal
,
2219 mVariableModuleGlobal
->NonVolatileLastVariableOffset
+ GetVariableHeaderSize (AuthFormat
),
2220 (UINT32
)(VarSize
- GetVariableHeaderSize (AuthFormat
)),
2221 (UINT8
*)NextVariable
+ GetVariableHeaderSize (AuthFormat
)
2224 if (EFI_ERROR (Status
)) {
2231 NextVariable
->State
= VAR_ADDED
;
2232 Status
= UpdateVariableStore (
2233 &mVariableModuleGlobal
->VariableGlobal
,
2237 mVariableModuleGlobal
->NonVolatileLastVariableOffset
+ OFFSET_OF (VARIABLE_HEADER
, State
),
2239 &NextVariable
->State
2242 if (EFI_ERROR (Status
)) {
2247 // Update the memory copy of Flash region.
2249 CopyMem ((UINT8
*)mNvVariableCache
+ mVariableModuleGlobal
->NonVolatileLastVariableOffset
, (UINT8
*)NextVariable
, VarSize
);
2252 // Emulated non-volatile variable mode.
2254 NextVariable
->State
= VAR_ADDED
;
2255 Status
= UpdateVariableStore (
2256 &mVariableModuleGlobal
->VariableGlobal
,
2260 mVariableModuleGlobal
->NonVolatileLastVariableOffset
,
2262 (UINT8
*)NextVariable
2265 if (EFI_ERROR (Status
)) {
2270 mVariableModuleGlobal
->NonVolatileLastVariableOffset
+= HEADER_ALIGN (VarSize
);
2272 if ((Attributes
& EFI_VARIABLE_HARDWARE_ERROR_RECORD
) != 0) {
2273 mVariableModuleGlobal
->HwErrVariableTotalSize
+= HEADER_ALIGN (VarSize
);
2275 mVariableModuleGlobal
->CommonVariableTotalSize
+= HEADER_ALIGN (VarSize
);
2276 if (IsCommonUserVariable
) {
2277 mVariableModuleGlobal
->CommonUserVariableTotalSize
+= HEADER_ALIGN (VarSize
);
2282 // Create a volatile variable.
2286 if ((UINT32
)(VarSize
+ mVariableModuleGlobal
->VolatileLastVariableOffset
) >
2287 ((VARIABLE_STORE_HEADER
*)((UINTN
)(mVariableModuleGlobal
->VariableGlobal
.VolatileVariableBase
)))->Size
)
2290 // Perform garbage collection & reclaim operation, and integrate the new variable at the same time.
2293 mVariableModuleGlobal
->VariableGlobal
.VolatileVariableBase
,
2294 &mVariableModuleGlobal
->VolatileLastVariableOffset
,
2298 HEADER_ALIGN (VarSize
)
2300 if (!EFI_ERROR (Status
)) {
2302 // The new variable has been integrated successfully during reclaiming.
2304 if (Variable
->CurrPtr
!= NULL
) {
2305 CacheVariable
->CurrPtr
= (VARIABLE_HEADER
*)((UINTN
)CacheVariable
->StartPtr
+ ((UINTN
)Variable
->CurrPtr
- (UINTN
)Variable
->StartPtr
));
2306 CacheVariable
->InDeletedTransitionPtr
= NULL
;
2309 UpdateVariableInfo (VariableName
, VendorGuid
, TRUE
, FALSE
, TRUE
, FALSE
, FALSE
, &gVariableInfo
);
2315 NextVariable
->State
= VAR_ADDED
;
2316 Status
= UpdateVariableStore (
2317 &mVariableModuleGlobal
->VariableGlobal
,
2321 mVariableModuleGlobal
->VolatileLastVariableOffset
,
2323 (UINT8
*)NextVariable
2326 if (EFI_ERROR (Status
)) {
2330 mVariableModuleGlobal
->VolatileLastVariableOffset
+= HEADER_ALIGN (VarSize
);
2334 // Mark the old variable as deleted.
2336 if (!EFI_ERROR (Status
) && (Variable
->CurrPtr
!= NULL
)) {
2337 if (Variable
->InDeletedTransitionPtr
!= NULL
) {
2339 // Both ADDED and IN_DELETED_TRANSITION old variable are present,
2340 // set IN_DELETED_TRANSITION one to DELETED state first.
2342 ASSERT (CacheVariable
->InDeletedTransitionPtr
!= NULL
);
2343 State
= CacheVariable
->InDeletedTransitionPtr
->State
;
2344 State
&= VAR_DELETED
;
2345 Status
= UpdateVariableStore (
2346 &mVariableModuleGlobal
->VariableGlobal
,
2350 (UINTN
)&Variable
->InDeletedTransitionPtr
->State
,
2354 if (!EFI_ERROR (Status
)) {
2355 if (!Variable
->Volatile
) {
2356 CacheVariable
->InDeletedTransitionPtr
->State
= State
;
2363 State
= CacheVariable
->CurrPtr
->State
;
2364 State
&= VAR_DELETED
;
2366 Status
= UpdateVariableStore (
2367 &mVariableModuleGlobal
->VariableGlobal
,
2371 (UINTN
)&Variable
->CurrPtr
->State
,
2375 if (!EFI_ERROR (Status
) && !Variable
->Volatile
) {
2376 CacheVariable
->CurrPtr
->State
= State
;
2380 if (!EFI_ERROR (Status
)) {
2381 UpdateVariableInfo (VariableName
, VendorGuid
, Volatile
, FALSE
, TRUE
, FALSE
, FALSE
, &gVariableInfo
);
2383 FlushHobVariableToFlash (VariableName
, VendorGuid
);
2388 if (!EFI_ERROR (Status
)) {
2389 if (((Variable
->CurrPtr
!= NULL
) && !Variable
->Volatile
) || ((Attributes
& EFI_VARIABLE_NON_VOLATILE
) != 0)) {
2390 VolatileCacheInstance
= &(mVariableModuleGlobal
->VariableGlobal
.VariableRuntimeCacheContext
.VariableRuntimeNvCache
);
2392 VolatileCacheInstance
= &(mVariableModuleGlobal
->VariableGlobal
.VariableRuntimeCacheContext
.VariableRuntimeVolatileCache
);
2395 if (VolatileCacheInstance
->Store
!= NULL
) {
2396 Status
= SynchronizeRuntimeVariableCache (
2397 VolatileCacheInstance
,
2399 VolatileCacheInstance
->Store
->Size
2401 ASSERT_EFI_ERROR (Status
);
2410 This code finds variable in storage blocks (Volatile or Non-Volatile).
2412 Caution: This function may receive untrusted input.
2413 This function may be invoked in SMM mode, and datasize is external input.
2414 This function will do basic validation, before parse the data.
2416 @param VariableName Name of Variable to be found.
2417 @param VendorGuid Variable vendor GUID.
2418 @param Attributes Attribute value of the variable found.
2419 @param DataSize Size of Data found. If size is less than the
2420 data, this value contains the required size.
2421 @param Data The buffer to return the contents of the variable. May be NULL
2422 with a zero DataSize in order to determine the size buffer needed.
2424 @return EFI_INVALID_PARAMETER Invalid parameter.
2425 @return EFI_SUCCESS Find the specified variable.
2426 @return EFI_NOT_FOUND Not found.
2427 @return EFI_BUFFER_TO_SMALL DataSize is too small for the result.
2432 VariableServiceGetVariable (
2433 IN CHAR16
*VariableName
,
2434 IN EFI_GUID
*VendorGuid
,
2435 OUT UINT32
*Attributes OPTIONAL
,
2436 IN OUT UINTN
*DataSize
,
2437 OUT VOID
*Data OPTIONAL
2441 VARIABLE_POINTER_TRACK Variable
;
2444 if ((VariableName
== NULL
) || (VendorGuid
== NULL
) || (DataSize
== NULL
)) {
2445 return EFI_INVALID_PARAMETER
;
2448 if (VariableName
[0] == 0) {
2449 return EFI_NOT_FOUND
;
2452 AcquireLockOnlyAtBootTime (&mVariableModuleGlobal
->VariableGlobal
.VariableServicesLock
);
2454 Status
= FindVariable (VariableName
, VendorGuid
, &Variable
, &mVariableModuleGlobal
->VariableGlobal
, FALSE
);
2455 if ((Variable
.CurrPtr
== NULL
) || EFI_ERROR (Status
)) {
2462 VarDataSize
= DataSizeOfVariable (Variable
.CurrPtr
, mVariableModuleGlobal
->VariableGlobal
.AuthFormat
);
2463 ASSERT (VarDataSize
!= 0);
2465 if (*DataSize
>= VarDataSize
) {
2467 Status
= EFI_INVALID_PARAMETER
;
2471 CopyMem (Data
, GetVariableDataPtr (Variable
.CurrPtr
, mVariableModuleGlobal
->VariableGlobal
.AuthFormat
), VarDataSize
);
2473 *DataSize
= VarDataSize
;
2474 UpdateVariableInfo (VariableName
, VendorGuid
, Variable
.Volatile
, TRUE
, FALSE
, FALSE
, FALSE
, &gVariableInfo
);
2476 Status
= EFI_SUCCESS
;
2479 *DataSize
= VarDataSize
;
2480 Status
= EFI_BUFFER_TOO_SMALL
;
2485 if ((Status
== EFI_SUCCESS
) || (Status
== EFI_BUFFER_TOO_SMALL
)) {
2486 if ((Attributes
!= NULL
) && (Variable
.CurrPtr
!= NULL
)) {
2487 *Attributes
= Variable
.CurrPtr
->Attributes
;
2491 ReleaseLockOnlyAtBootTime (&mVariableModuleGlobal
->VariableGlobal
.VariableServicesLock
);
2497 This code Finds the Next available variable.
2499 Caution: This function may receive untrusted input.
2500 This function may be invoked in SMM mode. This function will do basic validation, before parse the data.
2502 @param VariableNameSize The size of the VariableName buffer. The size must be large
2503 enough to fit input string supplied in VariableName buffer.
2504 @param VariableName Pointer to variable name.
2505 @param VendorGuid Variable Vendor Guid.
2507 @retval EFI_SUCCESS The function completed successfully.
2508 @retval EFI_NOT_FOUND The next variable was not found.
2509 @retval EFI_BUFFER_TOO_SMALL The VariableNameSize is too small for the result.
2510 VariableNameSize has been updated with the size needed to complete the request.
2511 @retval EFI_INVALID_PARAMETER VariableNameSize is NULL.
2512 @retval EFI_INVALID_PARAMETER VariableName is NULL.
2513 @retval EFI_INVALID_PARAMETER VendorGuid is NULL.
2514 @retval EFI_INVALID_PARAMETER The input values of VariableName and VendorGuid are not a name and
2515 GUID of an existing variable.
2516 @retval EFI_INVALID_PARAMETER Null-terminator is not found in the first VariableNameSize bytes of
2517 the input VariableName buffer.
2522 VariableServiceGetNextVariableName (
2523 IN OUT UINTN
*VariableNameSize
,
2524 IN OUT CHAR16
*VariableName
,
2525 IN OUT EFI_GUID
*VendorGuid
2532 VARIABLE_HEADER
*VariablePtr
;
2533 VARIABLE_STORE_HEADER
*VariableStoreHeader
[VariableStoreTypeMax
];
2535 if ((VariableNameSize
== NULL
) || (VariableName
== NULL
) || (VendorGuid
== NULL
)) {
2536 return EFI_INVALID_PARAMETER
;
2539 AuthFormat
= mVariableModuleGlobal
->VariableGlobal
.AuthFormat
;
2542 // Calculate the possible maximum length of name string, including the Null terminator.
2544 MaxLen
= *VariableNameSize
/ sizeof (CHAR16
);
2545 if ((MaxLen
== 0) || (StrnLenS (VariableName
, MaxLen
) == MaxLen
)) {
2547 // Null-terminator is not found in the first VariableNameSize bytes of the input VariableName buffer,
2548 // follow spec to return EFI_INVALID_PARAMETER.
2550 return EFI_INVALID_PARAMETER
;
2553 AcquireLockOnlyAtBootTime (&mVariableModuleGlobal
->VariableGlobal
.VariableServicesLock
);
2556 // 0: Volatile, 1: HOB, 2: Non-Volatile.
2557 // The index and attributes mapping must be kept in this order as FindVariable
2558 // makes use of this mapping to implement search algorithm.
2560 VariableStoreHeader
[VariableStoreTypeVolatile
] = (VARIABLE_STORE_HEADER
*)(UINTN
)mVariableModuleGlobal
->VariableGlobal
.VolatileVariableBase
;
2561 VariableStoreHeader
[VariableStoreTypeHob
] = (VARIABLE_STORE_HEADER
*)(UINTN
)mVariableModuleGlobal
->VariableGlobal
.HobVariableBase
;
2562 VariableStoreHeader
[VariableStoreTypeNv
] = mNvVariableCache
;
2564 Status
= VariableServiceGetNextVariableInternal (
2567 VariableStoreHeader
,
2571 if (!EFI_ERROR (Status
)) {
2572 VarNameSize
= NameSizeOfVariable (VariablePtr
, AuthFormat
);
2573 ASSERT (VarNameSize
!= 0);
2574 if (VarNameSize
<= *VariableNameSize
) {
2577 GetVariableNamePtr (VariablePtr
, AuthFormat
),
2582 GetVendorGuidPtr (VariablePtr
, AuthFormat
),
2585 Status
= EFI_SUCCESS
;
2587 Status
= EFI_BUFFER_TOO_SMALL
;
2590 *VariableNameSize
= VarNameSize
;
2593 ReleaseLockOnlyAtBootTime (&mVariableModuleGlobal
->VariableGlobal
.VariableServicesLock
);
2599 This code sets variable in storage blocks (Volatile or Non-Volatile).
2601 Caution: This function may receive untrusted input.
2602 This function may be invoked in SMM mode, and datasize and data are external input.
2603 This function will do basic validation, before parse the data.
2604 This function will parse the authentication carefully to avoid security issues, like
2605 buffer overflow, integer overflow.
2606 This function will check attribute carefully to avoid authentication bypass.
2608 @param VariableName Name of Variable to be found.
2609 @param VendorGuid Variable vendor GUID.
2610 @param Attributes Attribute value of the variable found
2611 @param DataSize Size of Data found. If size is less than the
2612 data, this value contains the required size.
2613 @param Data Data pointer.
2615 @return EFI_INVALID_PARAMETER Invalid parameter.
2616 @return EFI_SUCCESS Set successfully.
2617 @return EFI_OUT_OF_RESOURCES Resource not enough to set variable.
2618 @return EFI_NOT_FOUND Not found.
2619 @return EFI_WRITE_PROTECTED Variable is read-only.
2624 VariableServiceSetVariable (
2625 IN CHAR16
*VariableName
,
2626 IN EFI_GUID
*VendorGuid
,
2627 IN UINT32 Attributes
,
2632 VARIABLE_POINTER_TRACK Variable
;
2634 VARIABLE_HEADER
*NextVariable
;
2635 EFI_PHYSICAL_ADDRESS Point
;
2639 AuthFormat
= mVariableModuleGlobal
->VariableGlobal
.AuthFormat
;
2642 // Check input parameters.
2644 if ((VariableName
== NULL
) || (VariableName
[0] == 0) || (VendorGuid
== NULL
)) {
2645 return EFI_INVALID_PARAMETER
;
2648 if ((DataSize
!= 0) && (Data
== NULL
)) {
2649 return EFI_INVALID_PARAMETER
;
2653 // Check for reserverd bit in variable attribute.
2654 // EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS is deprecated but we still allow
2655 // the delete operation of common authenticated variable at user physical presence.
2656 // So leave EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS attribute check to AuthVariableLib
2658 if ((Attributes
& (~(EFI_VARIABLE_ATTRIBUTES_MASK
| EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS
))) != 0) {
2659 return EFI_INVALID_PARAMETER
;
2663 // Make sure if runtime bit is set, boot service bit is set also.
2665 if ((Attributes
& (EFI_VARIABLE_RUNTIME_ACCESS
| EFI_VARIABLE_BOOTSERVICE_ACCESS
)) == EFI_VARIABLE_RUNTIME_ACCESS
) {
2666 if ((Attributes
& EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS
) != 0) {
2667 return EFI_UNSUPPORTED
;
2669 return EFI_INVALID_PARAMETER
;
2671 } else if ((Attributes
& VARIABLE_ATTRIBUTE_AT_AW
) != 0) {
2672 if (!mVariableModuleGlobal
->VariableGlobal
.AuthSupport
) {
2674 // Not support authenticated variable write.
2676 return EFI_INVALID_PARAMETER
;
2678 } else if ((Attributes
& EFI_VARIABLE_HARDWARE_ERROR_RECORD
) != 0) {
2679 if (PcdGet32 (PcdHwErrStorageSize
) == 0) {
2681 // Not support harware error record variable variable.
2683 return EFI_INVALID_PARAMETER
;
2688 // EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS and EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS attribute
2689 // cannot be set both.
2691 if ( ((Attributes
& EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS
) == EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS
)
2692 && ((Attributes
& EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS
) == EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS
))
2694 return EFI_UNSUPPORTED
;
2697 if ((Attributes
& EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS
) == EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS
) {
2699 // If DataSize == AUTHINFO_SIZE and then PayloadSize is 0.
2700 // Maybe it's the delete operation of common authenticated variable at user physical presence.
2702 if (DataSize
!= AUTHINFO_SIZE
) {
2703 return EFI_UNSUPPORTED
;
2706 PayloadSize
= DataSize
- AUTHINFO_SIZE
;
2707 } else if ((Attributes
& EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS
) == EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS
) {
2709 // Sanity check for EFI_VARIABLE_AUTHENTICATION_2 descriptor.
2711 if ((DataSize
< OFFSET_OF_AUTHINFO2_CERT_DATA
) ||
2712 (((EFI_VARIABLE_AUTHENTICATION_2
*)Data
)->AuthInfo
.Hdr
.dwLength
> DataSize
- (OFFSET_OF (EFI_VARIABLE_AUTHENTICATION_2
, AuthInfo
))) ||
2713 (((EFI_VARIABLE_AUTHENTICATION_2
*)Data
)->AuthInfo
.Hdr
.dwLength
< OFFSET_OF (WIN_CERTIFICATE_UEFI_GUID
, CertData
)))
2715 return EFI_SECURITY_VIOLATION
;
2719 // The VariableSpeculationBarrier() call here is to ensure the above sanity
2720 // check for the EFI_VARIABLE_AUTHENTICATION_2 descriptor has been completed
2721 // before the execution of subsequent codes.
2723 VariableSpeculationBarrier ();
2724 PayloadSize
= DataSize
- AUTHINFO2_SIZE (Data
);
2726 PayloadSize
= DataSize
;
2729 if ((UINTN
)(~0) - PayloadSize
< StrSize (VariableName
)) {
2731 // Prevent whole variable size overflow
2733 return EFI_INVALID_PARAMETER
;
2737 // The size of the VariableName, including the Unicode Null in bytes plus
2738 // the DataSize is limited to maximum size of PcdGet32 (PcdMaxHardwareErrorVariableSize)
2739 // bytes for HwErrRec#### variable.
2741 if ((Attributes
& EFI_VARIABLE_HARDWARE_ERROR_RECORD
) == EFI_VARIABLE_HARDWARE_ERROR_RECORD
) {
2742 if (StrSize (VariableName
) + PayloadSize
>
2743 PcdGet32 (PcdMaxHardwareErrorVariableSize
) - GetVariableHeaderSize (AuthFormat
))
2745 return EFI_INVALID_PARAMETER
;
2749 // The size of the VariableName, including the Unicode Null in bytes plus
2750 // the DataSize is limited to maximum size of Max(Auth|Volatile)VariableSize bytes.
2752 if ((Attributes
& VARIABLE_ATTRIBUTE_AT_AW
) != 0) {
2753 if (StrSize (VariableName
) + PayloadSize
>
2754 mVariableModuleGlobal
->MaxAuthVariableSize
-
2755 GetVariableHeaderSize (AuthFormat
))
2759 "%a: Failed to set variable '%s' with Guid %g\n",
2766 "NameSize(0x%x) + PayloadSize(0x%x) > "
2767 "MaxAuthVariableSize(0x%x) - HeaderSize(0x%x)\n",
2768 StrSize (VariableName
),
2770 mVariableModuleGlobal
->MaxAuthVariableSize
,
2771 GetVariableHeaderSize (AuthFormat
)
2773 return EFI_INVALID_PARAMETER
;
2775 } else if ((Attributes
& EFI_VARIABLE_NON_VOLATILE
) != 0) {
2776 if (StrSize (VariableName
) + PayloadSize
>
2777 mVariableModuleGlobal
->MaxVariableSize
- GetVariableHeaderSize (AuthFormat
))
2781 "%a: Failed to set variable '%s' with Guid %g\n",
2788 "NameSize(0x%x) + PayloadSize(0x%x) > "
2789 "MaxVariableSize(0x%x) - HeaderSize(0x%x)\n",
2790 StrSize (VariableName
),
2792 mVariableModuleGlobal
->MaxVariableSize
,
2793 GetVariableHeaderSize (AuthFormat
)
2795 return EFI_INVALID_PARAMETER
;
2798 if (StrSize (VariableName
) + PayloadSize
>
2799 mVariableModuleGlobal
->MaxVolatileVariableSize
- GetVariableHeaderSize (AuthFormat
))
2803 "%a: Failed to set variable '%s' with Guid %g\n",
2810 "NameSize(0x%x) + PayloadSize(0x%x) > "
2811 "MaxVolatileVariableSize(0x%x) - HeaderSize(0x%x)\n",
2812 StrSize (VariableName
),
2814 mVariableModuleGlobal
->MaxVolatileVariableSize
,
2815 GetVariableHeaderSize (AuthFormat
)
2817 return EFI_INVALID_PARAMETER
;
2823 // Special Handling for MOR Lock variable.
2825 Status
= SetVariableCheckHandlerMor (VariableName
, VendorGuid
, Attributes
, PayloadSize
, (VOID
*)((UINTN
)Data
+ DataSize
- PayloadSize
));
2826 if (Status
== EFI_ALREADY_STARTED
) {
2828 // EFI_ALREADY_STARTED means the SetVariable() action is handled inside of SetVariableCheckHandlerMor().
2829 // Variable driver can just return SUCCESS.
2834 if (EFI_ERROR (Status
)) {
2838 Status
= VarCheckLibSetVariableCheck (VariableName
, VendorGuid
, Attributes
, PayloadSize
, (VOID
*)((UINTN
)Data
+ DataSize
- PayloadSize
), mRequestSource
);
2839 if (EFI_ERROR (Status
)) {
2843 AcquireLockOnlyAtBootTime (&mVariableModuleGlobal
->VariableGlobal
.VariableServicesLock
);
2846 // Consider reentrant in MCA/INIT/NMI. It needs be reupdated.
2848 if (1 < InterlockedIncrement (&mVariableModuleGlobal
->VariableGlobal
.ReentrantState
)) {
2849 Point
= mVariableModuleGlobal
->VariableGlobal
.NonVolatileVariableBase
;
2851 // Parse non-volatile variable data and get last variable offset.
2853 NextVariable
= GetStartPointer ((VARIABLE_STORE_HEADER
*)(UINTN
)Point
);
2854 while (IsValidVariableHeader (NextVariable
, GetEndPointer ((VARIABLE_STORE_HEADER
*)(UINTN
)Point
))) {
2855 NextVariable
= GetNextVariablePtr (NextVariable
, AuthFormat
);
2858 mVariableModuleGlobal
->NonVolatileLastVariableOffset
= (UINTN
)NextVariable
- (UINTN
)Point
;
2862 // Check whether the input variable is already existed.
2864 Status
= FindVariable (VariableName
, VendorGuid
, &Variable
, &mVariableModuleGlobal
->VariableGlobal
, TRUE
);
2865 if (!EFI_ERROR (Status
)) {
2866 if (((Variable
.CurrPtr
->Attributes
& EFI_VARIABLE_RUNTIME_ACCESS
) == 0) && AtRuntime ()) {
2867 Status
= EFI_WRITE_PROTECTED
;
2871 if ((Attributes
!= 0) && ((Attributes
& (~EFI_VARIABLE_APPEND_WRITE
)) != Variable
.CurrPtr
->Attributes
)) {
2873 // If a preexisting variable is rewritten with different attributes, SetVariable() shall not
2874 // modify the variable and shall return EFI_INVALID_PARAMETER. Two exceptions to this rule:
2875 // 1. No access attributes specified
2876 // 2. The only attribute differing is EFI_VARIABLE_APPEND_WRITE
2878 Status
= EFI_INVALID_PARAMETER
;
2879 DEBUG ((DEBUG_INFO
, "[Variable]: Rewritten a preexisting variable(0x%08x) with different attributes(0x%08x) - %g:%s\n", Variable
.CurrPtr
->Attributes
, Attributes
, VendorGuid
, VariableName
));
2884 if (!FeaturePcdGet (PcdUefiVariableDefaultLangDeprecate
)) {
2886 // Hook the operation of setting PlatformLangCodes/PlatformLang and LangCodes/Lang.
2888 Status
= AutoUpdateLangVariable (VariableName
, Data
, DataSize
);
2889 if (EFI_ERROR (Status
)) {
2891 // The auto update operation failed, directly return to avoid inconsistency between PlatformLang and Lang.
2897 if (mVariableModuleGlobal
->VariableGlobal
.AuthSupport
) {
2898 Status
= AuthVariableLibProcessVariable (VariableName
, VendorGuid
, Data
, DataSize
, Attributes
);
2900 Status
= UpdateVariable (VariableName
, VendorGuid
, Data
, DataSize
, Attributes
, 0, 0, &Variable
, NULL
);
2904 InterlockedDecrement (&mVariableModuleGlobal
->VariableGlobal
.ReentrantState
);
2905 ReleaseLockOnlyAtBootTime (&mVariableModuleGlobal
->VariableGlobal
.VariableServicesLock
);
2907 if (!AtRuntime ()) {
2908 if (!EFI_ERROR (Status
)) {
2921 This code returns information about the EFI variables.
2923 Caution: This function may receive untrusted input.
2924 This function may be invoked in SMM mode. This function will do basic validation, before parse the data.
2926 @param Attributes Attributes bitmask to specify the type of variables
2927 on which to return information.
2928 @param MaximumVariableStorageSize Pointer to the maximum size of the storage space available
2929 for the EFI variables associated with the attributes specified.
2930 @param RemainingVariableStorageSize Pointer to the remaining size of the storage space available
2931 for EFI variables associated with the attributes specified.
2932 @param MaximumVariableSize Pointer to the maximum size of an individual EFI variables
2933 associated with the attributes specified.
2935 @return EFI_SUCCESS Query successfully.
2940 VariableServiceQueryVariableInfoInternal (
2941 IN UINT32 Attributes
,
2942 OUT UINT64
*MaximumVariableStorageSize
,
2943 OUT UINT64
*RemainingVariableStorageSize
,
2944 OUT UINT64
*MaximumVariableSize
2947 VARIABLE_HEADER
*Variable
;
2948 VARIABLE_HEADER
*NextVariable
;
2949 UINT64 VariableSize
;
2950 VARIABLE_STORE_HEADER
*VariableStoreHeader
;
2951 UINT64 CommonVariableTotalSize
;
2952 UINT64 HwErrVariableTotalSize
;
2954 VARIABLE_POINTER_TRACK VariablePtrTrack
;
2956 CommonVariableTotalSize
= 0;
2957 HwErrVariableTotalSize
= 0;
2959 if ((Attributes
& EFI_VARIABLE_NON_VOLATILE
) == 0) {
2961 // Query is Volatile related.
2963 VariableStoreHeader
= (VARIABLE_STORE_HEADER
*)((UINTN
)mVariableModuleGlobal
->VariableGlobal
.VolatileVariableBase
);
2966 // Query is Non-Volatile related.
2968 VariableStoreHeader
= mNvVariableCache
;
2972 // Now let's fill *MaximumVariableStorageSize *RemainingVariableStorageSize
2973 // with the storage size (excluding the storage header size).
2975 *MaximumVariableStorageSize
= VariableStoreHeader
->Size
- sizeof (VARIABLE_STORE_HEADER
);
2978 // Harware error record variable needs larger size.
2980 if ((Attributes
& (EFI_VARIABLE_NON_VOLATILE
| EFI_VARIABLE_HARDWARE_ERROR_RECORD
)) == (EFI_VARIABLE_NON_VOLATILE
| EFI_VARIABLE_HARDWARE_ERROR_RECORD
)) {
2981 *MaximumVariableStorageSize
= PcdGet32 (PcdHwErrStorageSize
);
2982 *MaximumVariableSize
= PcdGet32 (PcdMaxHardwareErrorVariableSize
) -
2983 GetVariableHeaderSize (mVariableModuleGlobal
->VariableGlobal
.AuthFormat
);
2985 if ((Attributes
& EFI_VARIABLE_NON_VOLATILE
) != 0) {
2987 *MaximumVariableStorageSize
= mVariableModuleGlobal
->CommonRuntimeVariableSpace
;
2989 *MaximumVariableStorageSize
= mVariableModuleGlobal
->CommonVariableSpace
;
2994 // Let *MaximumVariableSize be Max(Auth|Volatile)VariableSize with the exception of the variable header size.
2996 if ((Attributes
& VARIABLE_ATTRIBUTE_AT_AW
) != 0) {
2997 *MaximumVariableSize
= mVariableModuleGlobal
->MaxAuthVariableSize
-
2998 GetVariableHeaderSize (mVariableModuleGlobal
->VariableGlobal
.AuthFormat
);
2999 } else if ((Attributes
& EFI_VARIABLE_NON_VOLATILE
) != 0) {
3000 *MaximumVariableSize
= mVariableModuleGlobal
->MaxVariableSize
-
3001 GetVariableHeaderSize (mVariableModuleGlobal
->VariableGlobal
.AuthFormat
);
3003 *MaximumVariableSize
= mVariableModuleGlobal
->MaxVolatileVariableSize
-
3004 GetVariableHeaderSize (mVariableModuleGlobal
->VariableGlobal
.AuthFormat
);
3009 // Point to the starting address of the variables.
3011 Variable
= GetStartPointer (VariableStoreHeader
);
3014 // Now walk through the related variable store.
3016 while (IsValidVariableHeader (Variable
, GetEndPointer (VariableStoreHeader
))) {
3017 NextVariable
= GetNextVariablePtr (Variable
, mVariableModuleGlobal
->VariableGlobal
.AuthFormat
);
3018 VariableSize
= (UINT64
)(UINTN
)NextVariable
- (UINT64
)(UINTN
)Variable
;
3022 // We don't take the state of the variables in mind
3023 // when calculating RemainingVariableStorageSize,
3024 // since the space occupied by variables not marked with
3025 // VAR_ADDED is not allowed to be reclaimed in Runtime.
3027 if ((Variable
->Attributes
& EFI_VARIABLE_HARDWARE_ERROR_RECORD
) == EFI_VARIABLE_HARDWARE_ERROR_RECORD
) {
3028 HwErrVariableTotalSize
+= VariableSize
;
3030 CommonVariableTotalSize
+= VariableSize
;
3034 // Only care about Variables with State VAR_ADDED, because
3035 // the space not marked as VAR_ADDED is reclaimable now.
3037 if (Variable
->State
== VAR_ADDED
) {
3038 if ((Variable
->Attributes
& EFI_VARIABLE_HARDWARE_ERROR_RECORD
) == EFI_VARIABLE_HARDWARE_ERROR_RECORD
) {
3039 HwErrVariableTotalSize
+= VariableSize
;
3041 CommonVariableTotalSize
+= VariableSize
;
3043 } else if (Variable
->State
== (VAR_IN_DELETED_TRANSITION
& VAR_ADDED
)) {
3045 // If it is a IN_DELETED_TRANSITION variable,
3046 // and there is not also a same ADDED one at the same time,
3047 // this IN_DELETED_TRANSITION variable is valid.
3049 VariablePtrTrack
.StartPtr
= GetStartPointer (VariableStoreHeader
);
3050 VariablePtrTrack
.EndPtr
= GetEndPointer (VariableStoreHeader
);
3051 Status
= FindVariableEx (
3052 GetVariableNamePtr (Variable
, mVariableModuleGlobal
->VariableGlobal
.AuthFormat
),
3053 GetVendorGuidPtr (Variable
, mVariableModuleGlobal
->VariableGlobal
.AuthFormat
),
3056 mVariableModuleGlobal
->VariableGlobal
.AuthFormat
3058 if (!EFI_ERROR (Status
) && (VariablePtrTrack
.CurrPtr
->State
!= VAR_ADDED
)) {
3059 if ((Variable
->Attributes
& EFI_VARIABLE_HARDWARE_ERROR_RECORD
) == EFI_VARIABLE_HARDWARE_ERROR_RECORD
) {
3060 HwErrVariableTotalSize
+= VariableSize
;
3062 CommonVariableTotalSize
+= VariableSize
;
3069 // Go to the next one.
3071 Variable
= NextVariable
;
3074 if ((Attributes
& EFI_VARIABLE_HARDWARE_ERROR_RECORD
) == EFI_VARIABLE_HARDWARE_ERROR_RECORD
) {
3075 *RemainingVariableStorageSize
= *MaximumVariableStorageSize
- HwErrVariableTotalSize
;
3077 if (*MaximumVariableStorageSize
< CommonVariableTotalSize
) {
3078 *RemainingVariableStorageSize
= 0;
3080 *RemainingVariableStorageSize
= *MaximumVariableStorageSize
- CommonVariableTotalSize
;
3084 if (*RemainingVariableStorageSize
< GetVariableHeaderSize (mVariableModuleGlobal
->VariableGlobal
.AuthFormat
)) {
3085 *MaximumVariableSize
= 0;
3086 } else if ((*RemainingVariableStorageSize
- GetVariableHeaderSize (mVariableModuleGlobal
->VariableGlobal
.AuthFormat
)) <
3087 *MaximumVariableSize
3090 *MaximumVariableSize
= *RemainingVariableStorageSize
-
3091 GetVariableHeaderSize (mVariableModuleGlobal
->VariableGlobal
.AuthFormat
);
3099 This code returns information about the EFI variables.
3101 Caution: This function may receive untrusted input.
3102 This function may be invoked in SMM mode. This function will do basic validation, before parse the data.
3104 @param Attributes Attributes bitmask to specify the type of variables
3105 on which to return information.
3106 @param MaximumVariableStorageSize Pointer to the maximum size of the storage space available
3107 for the EFI variables associated with the attributes specified.
3108 @param RemainingVariableStorageSize Pointer to the remaining size of the storage space available
3109 for EFI variables associated with the attributes specified.
3110 @param MaximumVariableSize Pointer to the maximum size of an individual EFI variables
3111 associated with the attributes specified.
3113 @return EFI_INVALID_PARAMETER An invalid combination of attribute bits was supplied.
3114 @return EFI_SUCCESS Query successfully.
3115 @return EFI_UNSUPPORTED The attribute is not supported on this platform.
3120 VariableServiceQueryVariableInfo (
3121 IN UINT32 Attributes
,
3122 OUT UINT64
*MaximumVariableStorageSize
,
3123 OUT UINT64
*RemainingVariableStorageSize
,
3124 OUT UINT64
*MaximumVariableSize
3129 if ((MaximumVariableStorageSize
== NULL
) || (RemainingVariableStorageSize
== NULL
) || (MaximumVariableSize
== NULL
) || (Attributes
== 0)) {
3130 return EFI_INVALID_PARAMETER
;
3133 if ((Attributes
& EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS
) != 0) {
3135 // Deprecated attribute, make this check as highest priority.
3137 return EFI_UNSUPPORTED
;
3140 if ((Attributes
& EFI_VARIABLE_ATTRIBUTES_MASK
) == 0) {
3142 // Make sure the Attributes combination is supported by the platform.
3144 return EFI_UNSUPPORTED
;
3145 } else if ((Attributes
& (EFI_VARIABLE_RUNTIME_ACCESS
| EFI_VARIABLE_BOOTSERVICE_ACCESS
)) == EFI_VARIABLE_RUNTIME_ACCESS
) {
3147 // Make sure if runtime bit is set, boot service bit is set also.
3149 return EFI_INVALID_PARAMETER
;
3150 } else if (AtRuntime () && ((Attributes
& EFI_VARIABLE_RUNTIME_ACCESS
) == 0)) {
3152 // Make sure RT Attribute is set if we are in Runtime phase.
3154 return EFI_INVALID_PARAMETER
;
3155 } else if ((Attributes
& (EFI_VARIABLE_NON_VOLATILE
| EFI_VARIABLE_HARDWARE_ERROR_RECORD
)) == EFI_VARIABLE_HARDWARE_ERROR_RECORD
) {
3157 // Make sure Hw Attribute is set with NV.
3159 return EFI_INVALID_PARAMETER
;
3160 } else if ((Attributes
& VARIABLE_ATTRIBUTE_AT_AW
) != 0) {
3161 if (!mVariableModuleGlobal
->VariableGlobal
.AuthSupport
) {
3163 // Not support authenticated variable write.
3165 return EFI_UNSUPPORTED
;
3167 } else if ((Attributes
& EFI_VARIABLE_HARDWARE_ERROR_RECORD
) != 0) {
3168 if (PcdGet32 (PcdHwErrStorageSize
) == 0) {
3170 // Not support harware error record variable variable.
3172 return EFI_UNSUPPORTED
;
3176 AcquireLockOnlyAtBootTime (&mVariableModuleGlobal
->VariableGlobal
.VariableServicesLock
);
3178 Status
= VariableServiceQueryVariableInfoInternal (
3180 MaximumVariableStorageSize
,
3181 RemainingVariableStorageSize
,
3185 ReleaseLockOnlyAtBootTime (&mVariableModuleGlobal
->VariableGlobal
.VariableServicesLock
);
3190 This function reclaims variable storage if free size is below the threshold.
3192 Caution: This function may be invoked at SMM mode.
3193 Care must be taken to make sure not security issue.
3202 UINTN RemainingCommonRuntimeVariableSpace
;
3203 UINTN RemainingHwErrVariableSpace
;
3204 STATIC BOOLEAN Reclaimed
;
3207 // This function will be called only once at EndOfDxe or ReadyToBoot event.
3215 Status
= EFI_SUCCESS
;
3217 if (mVariableModuleGlobal
->CommonRuntimeVariableSpace
< mVariableModuleGlobal
->CommonVariableTotalSize
) {
3218 RemainingCommonRuntimeVariableSpace
= 0;
3220 RemainingCommonRuntimeVariableSpace
= mVariableModuleGlobal
->CommonRuntimeVariableSpace
- mVariableModuleGlobal
->CommonVariableTotalSize
;
3223 RemainingHwErrVariableSpace
= PcdGet32 (PcdHwErrStorageSize
) - mVariableModuleGlobal
->HwErrVariableTotalSize
;
3226 // Check if the free area is below a threshold.
3228 if (((RemainingCommonRuntimeVariableSpace
< mVariableModuleGlobal
->MaxVariableSize
) ||
3229 (RemainingCommonRuntimeVariableSpace
< mVariableModuleGlobal
->MaxAuthVariableSize
)) ||
3230 ((PcdGet32 (PcdHwErrStorageSize
) != 0) &&
3231 (RemainingHwErrVariableSpace
< PcdGet32 (PcdMaxHardwareErrorVariableSize
))))
3234 mVariableModuleGlobal
->VariableGlobal
.NonVolatileVariableBase
,
3235 &mVariableModuleGlobal
->NonVolatileLastVariableOffset
,
3241 ASSERT_EFI_ERROR (Status
);
3246 Get maximum variable size, covering both non-volatile and volatile variables.
3248 @return Maximum variable size.
3252 GetMaxVariableSize (
3256 UINTN MaxVariableSize
;
3258 MaxVariableSize
= GetNonVolatileMaxVariableSize ();
3260 // The condition below fails implicitly if PcdMaxVolatileVariableSize equals
3261 // the default zero value.
3263 if (MaxVariableSize
< PcdGet32 (PcdMaxVolatileVariableSize
)) {
3264 MaxVariableSize
= PcdGet32 (PcdMaxVolatileVariableSize
);
3267 return MaxVariableSize
;
3271 Flush the HOB variable to flash.
3273 @param[in] VariableName Name of variable has been updated or deleted.
3274 @param[in] VendorGuid Guid of variable has been updated or deleted.
3278 FlushHobVariableToFlash (
3279 IN CHAR16
*VariableName
,
3280 IN EFI_GUID
*VendorGuid
3284 VARIABLE_STORE_HEADER
*VariableStoreHeader
;
3285 VARIABLE_HEADER
*Variable
;
3287 VARIABLE_POINTER_TRACK VariablePtrTrack
;
3292 AuthFormat
= mVariableModuleGlobal
->VariableGlobal
.AuthFormat
;
3295 // Flush the HOB variable to flash.
3297 if (mVariableModuleGlobal
->VariableGlobal
.HobVariableBase
!= 0) {
3298 VariableStoreHeader
= (VARIABLE_STORE_HEADER
*)(UINTN
)mVariableModuleGlobal
->VariableGlobal
.HobVariableBase
;
3300 // Set HobVariableBase to 0, it can avoid SetVariable to call back.
3302 mVariableModuleGlobal
->VariableGlobal
.HobVariableBase
= 0;
3303 for ( Variable
= GetStartPointer (VariableStoreHeader
)
3304 ; IsValidVariableHeader (Variable
, GetEndPointer (VariableStoreHeader
))
3305 ; Variable
= GetNextVariablePtr (Variable
, AuthFormat
)
3308 if (Variable
->State
!= VAR_ADDED
) {
3310 // The HOB variable has been set to DELETED state in local.
3315 ASSERT ((Variable
->Attributes
& EFI_VARIABLE_NON_VOLATILE
) != 0);
3316 if ((VendorGuid
== NULL
) || (VariableName
== NULL
) ||
3317 !CompareGuid (VendorGuid
, GetVendorGuidPtr (Variable
, AuthFormat
)) ||
3318 (StrCmp (VariableName
, GetVariableNamePtr (Variable
, AuthFormat
)) != 0))
3320 VariableData
= GetVariableDataPtr (Variable
, AuthFormat
);
3322 GetVariableNamePtr (Variable
, AuthFormat
),
3323 GetVendorGuidPtr (Variable
, AuthFormat
),
3325 &mVariableModuleGlobal
->VariableGlobal
,
3328 Status
= UpdateVariable (
3329 GetVariableNamePtr (Variable
, AuthFormat
),
3330 GetVendorGuidPtr (Variable
, AuthFormat
),
3332 DataSizeOfVariable (Variable
, AuthFormat
),
3333 Variable
->Attributes
,
3341 "Variable driver flush the HOB variable to flash: %g %s %r\n",
3342 GetVendorGuidPtr (Variable
, AuthFormat
),
3343 GetVariableNamePtr (Variable
, AuthFormat
),
3348 // The updated or deleted variable is matched with this HOB variable.
3349 // Don't break here because we will try to set other HOB variables
3350 // since this variable could be set successfully.
3352 Status
= EFI_SUCCESS
;
3355 if (!EFI_ERROR (Status
)) {
3357 // If set variable successful, or the updated or deleted variable is matched with the HOB variable,
3358 // set the HOB variable to DELETED state in local.
3362 "Variable driver set the HOB variable to DELETED state in local: %g %s\n",
3363 GetVendorGuidPtr (Variable
, AuthFormat
),
3364 GetVariableNamePtr (Variable
, AuthFormat
)
3366 Variable
->State
&= VAR_DELETED
;
3372 if (mVariableModuleGlobal
->VariableGlobal
.VariableRuntimeCacheContext
.VariableRuntimeHobCache
.Store
!= NULL
) {
3373 Status
= SynchronizeRuntimeVariableCache (
3374 &mVariableModuleGlobal
->VariableGlobal
.VariableRuntimeCacheContext
.VariableRuntimeHobCache
,
3376 mVariableModuleGlobal
->VariableGlobal
.VariableRuntimeCacheContext
.VariableRuntimeHobCache
.Store
->Size
3378 ASSERT_EFI_ERROR (Status
);
3383 // We still have HOB variable(s) not flushed in flash.
3385 mVariableModuleGlobal
->VariableGlobal
.HobVariableBase
= (EFI_PHYSICAL_ADDRESS
)(UINTN
)VariableStoreHeader
;
3388 // All HOB variables have been flushed in flash.
3390 DEBUG ((DEBUG_INFO
, "Variable driver: all HOB variables have been flushed in flash.\n"));
3391 if (mVariableModuleGlobal
->VariableGlobal
.VariableRuntimeCacheContext
.HobFlushComplete
!= NULL
) {
3392 *(mVariableModuleGlobal
->VariableGlobal
.VariableRuntimeCacheContext
.HobFlushComplete
) = TRUE
;
3395 if (!AtRuntime ()) {
3396 FreePool ((VOID
*)VariableStoreHeader
);
3403 Initializes variable write service.
3405 @retval EFI_SUCCESS Function successfully executed.
3406 @retval Others Fail to initialize the variable service.
3410 VariableWriteServiceInitialize (
3417 VARIABLE_ENTRY_PROPERTY
*VariableEntry
;
3419 AcquireLockOnlyAtBootTime (&mVariableModuleGlobal
->VariableGlobal
.VariableServicesLock
);
3422 // Check if the free area is really free.
3424 for (Index
= mVariableModuleGlobal
->NonVolatileLastVariableOffset
; Index
< mNvVariableCache
->Size
; Index
++) {
3425 Data
= ((UINT8
*)mNvVariableCache
)[Index
];
3428 // There must be something wrong in variable store, do reclaim operation.
3431 mVariableModuleGlobal
->VariableGlobal
.NonVolatileVariableBase
,
3432 &mVariableModuleGlobal
->NonVolatileLastVariableOffset
,
3438 if (EFI_ERROR (Status
)) {
3439 ReleaseLockOnlyAtBootTime (&mVariableModuleGlobal
->VariableGlobal
.VariableServicesLock
);
3447 FlushHobVariableToFlash (NULL
, NULL
);
3449 Status
= EFI_SUCCESS
;
3450 ZeroMem (&mAuthContextOut
, sizeof (mAuthContextOut
));
3451 if (mVariableModuleGlobal
->VariableGlobal
.AuthFormat
) {
3453 // Authenticated variable initialize.
3455 mAuthContextIn
.StructSize
= sizeof (AUTH_VAR_LIB_CONTEXT_IN
);
3456 mAuthContextIn
.MaxAuthVariableSize
= mVariableModuleGlobal
->MaxAuthVariableSize
-
3457 GetVariableHeaderSize (mVariableModuleGlobal
->VariableGlobal
.AuthFormat
);
3458 Status
= AuthVariableLibInitialize (&mAuthContextIn
, &mAuthContextOut
);
3459 if (!EFI_ERROR (Status
)) {
3460 DEBUG ((DEBUG_INFO
, "Variable driver will work with auth variable support!\n"));
3461 mVariableModuleGlobal
->VariableGlobal
.AuthSupport
= TRUE
;
3462 if (mAuthContextOut
.AuthVarEntry
!= NULL
) {
3463 for (Index
= 0; Index
< mAuthContextOut
.AuthVarEntryCount
; Index
++) {
3464 VariableEntry
= &mAuthContextOut
.AuthVarEntry
[Index
];
3465 Status
= VarCheckLibVariablePropertySet (
3466 VariableEntry
->Name
,
3467 VariableEntry
->Guid
,
3468 &VariableEntry
->VariableProperty
3470 ASSERT_EFI_ERROR (Status
);
3473 } else if (Status
== EFI_UNSUPPORTED
) {
3474 DEBUG ((DEBUG_INFO
, "NOTICE - AuthVariableLibInitialize() returns %r!\n", Status
));
3475 DEBUG ((DEBUG_INFO
, "Variable driver will continue to work without auth variable support!\n"));
3476 mVariableModuleGlobal
->VariableGlobal
.AuthSupport
= FALSE
;
3477 Status
= EFI_SUCCESS
;
3481 if (!EFI_ERROR (Status
)) {
3482 for (Index
= 0; Index
< ARRAY_SIZE (mVariableEntryProperty
); Index
++) {
3483 VariableEntry
= &mVariableEntryProperty
[Index
];
3484 Status
= VarCheckLibVariablePropertySet (VariableEntry
->Name
, VariableEntry
->Guid
, &VariableEntry
->VariableProperty
);
3485 ASSERT_EFI_ERROR (Status
);
3489 ReleaseLockOnlyAtBootTime (&mVariableModuleGlobal
->VariableGlobal
.VariableServicesLock
);
3492 // Initialize MOR Lock variable.
3500 Convert normal variable storage to the allocated auth variable storage.
3502 @param[in] NormalVarStorage Pointer to the normal variable storage header
3504 @retval the allocated auth variable storage
3507 ConvertNormalVarStorageToAuthVarStorage (
3508 VARIABLE_STORE_HEADER
*NormalVarStorage
3511 VARIABLE_HEADER
*StartPtr
;
3513 VARIABLE_HEADER
*EndPtr
;
3514 UINTN AuthVarStroageSize
;
3515 AUTHENTICATED_VARIABLE_HEADER
*AuthStartPtr
;
3516 VARIABLE_STORE_HEADER
*AuthVarStorage
;
3518 AuthVarStroageSize
= sizeof (VARIABLE_STORE_HEADER
);
3520 // Set AuthFormat as FALSE for normal variable storage
3522 mVariableModuleGlobal
->VariableGlobal
.AuthFormat
= FALSE
;
3525 // Calculate Auth Variable Storage Size
3527 StartPtr
= GetStartPointer (NormalVarStorage
);
3528 EndPtr
= GetEndPointer (NormalVarStorage
);
3529 while (StartPtr
< EndPtr
) {
3530 if (StartPtr
->State
== VAR_ADDED
) {
3531 AuthVarStroageSize
= HEADER_ALIGN (AuthVarStroageSize
);
3532 AuthVarStroageSize
+= sizeof (AUTHENTICATED_VARIABLE_HEADER
);
3533 AuthVarStroageSize
+= StartPtr
->NameSize
+ GET_PAD_SIZE (StartPtr
->NameSize
);
3534 AuthVarStroageSize
+= StartPtr
->DataSize
+ GET_PAD_SIZE (StartPtr
->DataSize
);
3537 StartPtr
= GetNextVariablePtr (StartPtr
, mVariableModuleGlobal
->VariableGlobal
.AuthFormat
);
3541 // Allocate Runtime memory for Auth Variable Storage
3543 AuthVarStorage
= AllocateRuntimeZeroPool (AuthVarStroageSize
);
3544 ASSERT (AuthVarStorage
!= NULL
);
3545 if (AuthVarStorage
== NULL
) {
3550 // Copy Variable from Normal storage to Auth storage
3552 StartPtr
= GetStartPointer (NormalVarStorage
);
3553 EndPtr
= GetEndPointer (NormalVarStorage
);
3554 AuthStartPtr
= (AUTHENTICATED_VARIABLE_HEADER
*)GetStartPointer (AuthVarStorage
);
3555 while (StartPtr
< EndPtr
) {
3556 if (StartPtr
->State
== VAR_ADDED
) {
3557 AuthStartPtr
= (AUTHENTICATED_VARIABLE_HEADER
*)HEADER_ALIGN (AuthStartPtr
);
3559 // Copy Variable Header
3561 AuthStartPtr
->StartId
= StartPtr
->StartId
;
3562 AuthStartPtr
->State
= StartPtr
->State
;
3563 AuthStartPtr
->Attributes
= StartPtr
->Attributes
;
3564 AuthStartPtr
->NameSize
= StartPtr
->NameSize
;
3565 AuthStartPtr
->DataSize
= StartPtr
->DataSize
;
3566 CopyGuid (&AuthStartPtr
->VendorGuid
, &StartPtr
->VendorGuid
);
3568 // Copy Variable Name
3570 NextPtr
= (UINT8
*)(AuthStartPtr
+ 1);
3573 GetVariableNamePtr (StartPtr
, mVariableModuleGlobal
->VariableGlobal
.AuthFormat
),
3574 AuthStartPtr
->NameSize
3577 // Copy Variable Data
3579 NextPtr
= NextPtr
+ AuthStartPtr
->NameSize
+ GET_PAD_SIZE (AuthStartPtr
->NameSize
);
3580 CopyMem (NextPtr
, GetVariableDataPtr (StartPtr
, mVariableModuleGlobal
->VariableGlobal
.AuthFormat
), AuthStartPtr
->DataSize
);
3582 // Go to next variable
3584 AuthStartPtr
= (AUTHENTICATED_VARIABLE_HEADER
*)(NextPtr
+ AuthStartPtr
->DataSize
+ GET_PAD_SIZE (AuthStartPtr
->DataSize
));
3587 StartPtr
= GetNextVariablePtr (StartPtr
, mVariableModuleGlobal
->VariableGlobal
.AuthFormat
);
3591 // Update Auth Storage Header
3593 AuthVarStorage
->Format
= NormalVarStorage
->Format
;
3594 AuthVarStorage
->State
= NormalVarStorage
->State
;
3595 AuthVarStorage
->Size
= (UINT32
)((UINTN
)AuthStartPtr
- (UINTN
)AuthVarStorage
);
3596 CopyGuid (&AuthVarStorage
->Signature
, &gEfiAuthenticatedVariableGuid
);
3597 ASSERT (AuthVarStorage
->Size
<= AuthVarStroageSize
);
3600 // Restore AuthFormat
3602 mVariableModuleGlobal
->VariableGlobal
.AuthFormat
= TRUE
;
3603 return AuthVarStorage
;
3607 Get HOB variable store.
3609 @param[in] VariableGuid NV variable store signature.
3611 @retval EFI_SUCCESS Function successfully executed.
3612 @retval EFI_OUT_OF_RESOURCES Fail to allocate enough memory resource.
3616 GetHobVariableStore (
3617 IN EFI_GUID
*VariableGuid
3620 VARIABLE_STORE_HEADER
*VariableStoreHeader
;
3621 UINT64 VariableStoreLength
;
3622 EFI_HOB_GUID_TYPE
*GuidHob
;
3623 BOOLEAN NeedConvertNormalToAuth
;
3626 // Make sure there is no more than one Variable HOB.
3628 DEBUG_CODE_BEGIN ();
3629 GuidHob
= GetFirstGuidHob (&gEfiAuthenticatedVariableGuid
);
3630 if (GuidHob
!= NULL
) {
3631 if ((GetNextGuidHob (&gEfiAuthenticatedVariableGuid
, GET_NEXT_HOB (GuidHob
)) != NULL
)) {
3632 DEBUG ((DEBUG_ERROR
, "ERROR: Found two Auth Variable HOBs\n"));
3634 } else if (GetFirstGuidHob (&gEfiVariableGuid
) != NULL
) {
3635 DEBUG ((DEBUG_ERROR
, "ERROR: Found one Auth + one Normal Variable HOBs\n"));
3639 GuidHob
= GetFirstGuidHob (&gEfiVariableGuid
);
3640 if (GuidHob
!= NULL
) {
3641 if ((GetNextGuidHob (&gEfiVariableGuid
, GET_NEXT_HOB (GuidHob
)) != NULL
)) {
3642 DEBUG ((DEBUG_ERROR
, "ERROR: Found two Normal Variable HOBs\n"));
3651 // Combinations supported:
3652 // 1. Normal NV variable store +
3653 // Normal HOB variable store
3654 // 2. Auth NV variable store +
3655 // Auth HOB variable store
3656 // 3. Auth NV variable store +
3657 // Normal HOB variable store (code will convert it to Auth Format)
3659 NeedConvertNormalToAuth
= FALSE
;
3660 GuidHob
= GetFirstGuidHob (VariableGuid
);
3661 if ((GuidHob
== NULL
) && (VariableGuid
== &gEfiAuthenticatedVariableGuid
)) {
3663 // Try getting it from normal variable HOB
3665 GuidHob
= GetFirstGuidHob (&gEfiVariableGuid
);
3666 NeedConvertNormalToAuth
= TRUE
;
3669 if (GuidHob
!= NULL
) {
3670 VariableStoreHeader
= GET_GUID_HOB_DATA (GuidHob
);
3671 VariableStoreLength
= GuidHob
->Header
.HobLength
- sizeof (EFI_HOB_GUID_TYPE
);
3672 if (GetVariableStoreStatus (VariableStoreHeader
) == EfiValid
) {
3673 if (!NeedConvertNormalToAuth
) {
3674 mVariableModuleGlobal
->VariableGlobal
.HobVariableBase
= (EFI_PHYSICAL_ADDRESS
)(UINTN
)AllocateRuntimeCopyPool ((UINTN
)VariableStoreLength
, (VOID
*)VariableStoreHeader
);
3676 mVariableModuleGlobal
->VariableGlobal
.HobVariableBase
= (EFI_PHYSICAL_ADDRESS
)(UINTN
)ConvertNormalVarStorageToAuthVarStorage ((VOID
*)VariableStoreHeader
);
3679 if (mVariableModuleGlobal
->VariableGlobal
.HobVariableBase
== 0) {
3680 return EFI_OUT_OF_RESOURCES
;
3683 DEBUG ((DEBUG_ERROR
, "HOB Variable Store header is corrupted!\n"));
3691 Initializes variable store area for non-volatile and volatile variable.
3693 @retval EFI_SUCCESS Function successfully executed.
3694 @retval EFI_OUT_OF_RESOURCES Fail to allocate enough memory resource.
3698 VariableCommonInitialize (
3703 VARIABLE_STORE_HEADER
*VolatileVariableStore
;
3705 EFI_GUID
*VariableGuid
;
3708 // Allocate runtime memory for variable driver global structure.
3710 mVariableModuleGlobal
= AllocateRuntimeZeroPool (sizeof (VARIABLE_MODULE_GLOBAL
));
3711 if (mVariableModuleGlobal
== NULL
) {
3712 return EFI_OUT_OF_RESOURCES
;
3715 InitializeLock (&mVariableModuleGlobal
->VariableGlobal
.VariableServicesLock
, TPL_NOTIFY
);
3718 // Init non-volatile variable store.
3720 Status
= InitNonVolatileVariableStore ();
3721 if (EFI_ERROR (Status
)) {
3722 FreePool (mVariableModuleGlobal
);
3727 // mVariableModuleGlobal->VariableGlobal.AuthFormat
3728 // has been initialized in InitNonVolatileVariableStore().
3730 if (mVariableModuleGlobal
->VariableGlobal
.AuthFormat
) {
3731 DEBUG ((DEBUG_INFO
, "Variable driver will work with auth variable format!\n"));
3733 // Set AuthSupport to FALSE first, VariableWriteServiceInitialize() will initialize it.
3735 mVariableModuleGlobal
->VariableGlobal
.AuthSupport
= FALSE
;
3736 VariableGuid
= &gEfiAuthenticatedVariableGuid
;
3738 DEBUG ((DEBUG_INFO
, "Variable driver will work without auth variable support!\n"));
3739 mVariableModuleGlobal
->VariableGlobal
.AuthSupport
= FALSE
;
3740 VariableGuid
= &gEfiVariableGuid
;
3744 // Get HOB variable store.
3746 Status
= GetHobVariableStore (VariableGuid
);
3747 if (EFI_ERROR (Status
)) {
3748 if (mNvFvHeaderCache
!= NULL
) {
3749 FreePool (mNvFvHeaderCache
);
3752 FreePool (mVariableModuleGlobal
);
3756 mVariableModuleGlobal
->MaxVolatileVariableSize
= ((PcdGet32 (PcdMaxVolatileVariableSize
) != 0) ?
3757 PcdGet32 (PcdMaxVolatileVariableSize
) :
3758 mVariableModuleGlobal
->MaxVariableSize
3761 // Allocate memory for volatile variable store, note that there is a scratch space to store scratch data.
3763 ScratchSize
= GetMaxVariableSize ();
3764 mVariableModuleGlobal
->ScratchBufferSize
= ScratchSize
;
3765 VolatileVariableStore
= AllocateRuntimePool (PcdGet32 (PcdVariableStoreSize
) + ScratchSize
);
3766 if (VolatileVariableStore
== NULL
) {
3767 if (mVariableModuleGlobal
->VariableGlobal
.HobVariableBase
!= 0) {
3768 FreePool ((VOID
*)(UINTN
)mVariableModuleGlobal
->VariableGlobal
.HobVariableBase
);
3771 if (mNvFvHeaderCache
!= NULL
) {
3772 FreePool (mNvFvHeaderCache
);
3775 FreePool (mVariableModuleGlobal
);
3776 return EFI_OUT_OF_RESOURCES
;
3779 SetMem (VolatileVariableStore
, PcdGet32 (PcdVariableStoreSize
) + ScratchSize
, 0xff);
3782 // Initialize Variable Specific Data.
3784 mVariableModuleGlobal
->VariableGlobal
.VolatileVariableBase
= (EFI_PHYSICAL_ADDRESS
)(UINTN
)VolatileVariableStore
;
3785 mVariableModuleGlobal
->VolatileLastVariableOffset
= (UINTN
)GetStartPointer (VolatileVariableStore
) - (UINTN
)VolatileVariableStore
;
3787 CopyGuid (&VolatileVariableStore
->Signature
, VariableGuid
);
3788 VolatileVariableStore
->Size
= PcdGet32 (PcdVariableStoreSize
);
3789 VolatileVariableStore
->Format
= VARIABLE_STORE_FORMATTED
;
3790 VolatileVariableStore
->State
= VARIABLE_STORE_HEALTHY
;
3791 VolatileVariableStore
->Reserved
= 0;
3792 VolatileVariableStore
->Reserved1
= 0;
3798 Get the proper fvb handle and/or fvb protocol by the given Flash address.
3800 @param[in] Address The Flash address.
3801 @param[out] FvbHandle In output, if it is not NULL, it points to the proper FVB handle.
3802 @param[out] FvbProtocol In output, if it is not NULL, it points to the proper FVB protocol.
3806 GetFvbInfoByAddress (
3807 IN EFI_PHYSICAL_ADDRESS Address
,
3808 OUT EFI_HANDLE
*FvbHandle OPTIONAL
,
3809 OUT EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
**FvbProtocol OPTIONAL
3813 EFI_HANDLE
*HandleBuffer
;
3816 EFI_PHYSICAL_ADDRESS FvbBaseAddress
;
3817 EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*Fvb
;
3818 EFI_FVB_ATTRIBUTES_2 Attributes
;
3820 UINTN NumberOfBlocks
;
3822 HandleBuffer
= NULL
;
3824 // Get all FVB handles.
3826 Status
= GetFvbCountAndBuffer (&HandleCount
, &HandleBuffer
);
3827 if (EFI_ERROR (Status
)) {
3828 return EFI_NOT_FOUND
;
3832 // Get the FVB to access variable store.
3835 for (Index
= 0; Index
< HandleCount
; Index
+= 1, Status
= EFI_NOT_FOUND
, Fvb
= NULL
) {
3836 Status
= GetFvbByHandle (HandleBuffer
[Index
], &Fvb
);
3837 if (EFI_ERROR (Status
)) {
3838 Status
= EFI_NOT_FOUND
;
3843 // Ensure this FVB protocol supported Write operation.
3845 Status
= Fvb
->GetAttributes (Fvb
, &Attributes
);
3846 if (EFI_ERROR (Status
) || ((Attributes
& EFI_FVB2_WRITE_STATUS
) == 0)) {
3851 // Compare the address and select the right one.
3853 Status
= Fvb
->GetPhysicalAddress (Fvb
, &FvbBaseAddress
);
3854 if (EFI_ERROR (Status
)) {
3859 // Assume one FVB has one type of BlockSize.
3861 Status
= Fvb
->GetBlockSize (Fvb
, 0, &BlockSize
, &NumberOfBlocks
);
3862 if (EFI_ERROR (Status
)) {
3866 if ((Address
>= FvbBaseAddress
) && (Address
< (FvbBaseAddress
+ BlockSize
* NumberOfBlocks
))) {
3867 if (FvbHandle
!= NULL
) {
3868 *FvbHandle
= HandleBuffer
[Index
];
3871 if (FvbProtocol
!= NULL
) {
3875 Status
= EFI_SUCCESS
;
3880 FreePool (HandleBuffer
);
3883 Status
= EFI_NOT_FOUND
;