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 - 2019, Intel Corporation. All rights reserved.<BR>
20 (C) Copyright 2015-2018 Hewlett Packard Enterprise Development LP<BR>
21 SPDX-License-Identifier: BSD-2-Clause-Patent
26 #include "VariableParsing.h"
28 VARIABLE_MODULE_GLOBAL
*mVariableModuleGlobal
;
31 /// Define a memory cache that improves the search performance for a variable.
32 /// For EmuNvMode == TRUE, it will be equal to NonVolatileVariableBase.
34 VARIABLE_STORE_HEADER
*mNvVariableCache
= NULL
;
37 /// Memory cache of Fv Header.
39 EFI_FIRMWARE_VOLUME_HEADER
*mNvFvHeaderCache
= NULL
;
42 /// The memory entry used for variable statistics data.
44 VARIABLE_INFO_ENTRY
*gVariableInfo
= NULL
;
47 /// The flag to indicate whether the platform has left the DXE phase of execution.
49 BOOLEAN mEndOfDxe
= FALSE
;
52 /// It indicates the var check request source.
53 /// In the implementation, DXE is regarded as untrusted, and SMM is trusted.
55 VAR_CHECK_REQUEST_SOURCE mRequestSource
= VarCheckFromUntrusted
;
58 // It will record the current boot error flag before EndOfDxe.
60 VAR_ERROR_FLAG mCurrentBootVarErrFlag
= VAR_ERROR_FLAG_NO_ERROR
;
62 VARIABLE_ENTRY_PROPERTY mVariableEntryProperty
[] = {
64 &gEdkiiVarErrorFlagGuid
,
67 VAR_CHECK_VARIABLE_PROPERTY_REVISION
,
68 VAR_CHECK_VARIABLE_PROPERTY_READ_ONLY
,
69 VARIABLE_ATTRIBUTE_NV_BS_RT
,
70 sizeof (VAR_ERROR_FLAG
),
71 sizeof (VAR_ERROR_FLAG
)
76 AUTH_VAR_LIB_CONTEXT_IN mAuthContextIn
= {
77 AUTH_VAR_LIB_CONTEXT_IN_STRUCT_VERSION
,
79 // StructSize, TO BE FILLED
83 // MaxAuthVariableSize, TO BE FILLED
86 VariableExLibFindVariable
,
87 VariableExLibFindNextVariable
,
88 VariableExLibUpdateVariable
,
89 VariableExLibGetScratchBuffer
,
90 VariableExLibCheckRemainingSpaceForConsistency
,
91 VariableExLibAtRuntime
,
94 AUTH_VAR_LIB_CONTEXT_OUT mAuthContextOut
;
98 This function writes data to the FWH at the correct LBA even if the LBAs
101 @param Global Pointer to VARAIBLE_GLOBAL structure.
102 @param Volatile Point out the Variable is Volatile or Non-Volatile.
103 @param SetByIndex TRUE if target pointer is given as index.
104 FALSE if target pointer is absolute.
105 @param Fvb Pointer to the writable FVB protocol.
106 @param DataPtrIndex Pointer to the Data from the end of VARIABLE_STORE_HEADER
108 @param DataSize Size of data to be written.
109 @param Buffer Pointer to the buffer from which data is written.
111 @retval EFI_INVALID_PARAMETER Parameters not valid.
112 @retval EFI_UNSUPPORTED Fvb is a NULL for Non-Volatile variable update.
113 @retval EFI_OUT_OF_RESOURCES The remaining size is not enough.
114 @retval EFI_SUCCESS Variable store successfully updated.
118 UpdateVariableStore (
119 IN VARIABLE_GLOBAL
*Global
,
121 IN BOOLEAN SetByIndex
,
122 IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*Fvb
,
123 IN UINTN DataPtrIndex
,
128 EFI_FV_BLOCK_MAP_ENTRY
*PtrBlockMapEntry
;
136 VARIABLE_STORE_HEADER
*VolatileBase
;
137 EFI_PHYSICAL_ADDRESS FvVolHdr
;
138 EFI_PHYSICAL_ADDRESS DataPtr
;
142 DataPtr
= DataPtrIndex
;
145 // Check if the Data is Volatile.
147 if (!Volatile
&& !mVariableModuleGlobal
->VariableGlobal
.EmuNvMode
) {
149 return EFI_UNSUPPORTED
;
151 Status
= Fvb
->GetPhysicalAddress(Fvb
, &FvVolHdr
);
152 ASSERT_EFI_ERROR (Status
);
155 // Data Pointer should point to the actual Address where data is to be
159 DataPtr
+= mVariableModuleGlobal
->VariableGlobal
.NonVolatileVariableBase
;
162 if ((DataPtr
+ DataSize
) > (FvVolHdr
+ mNvFvHeaderCache
->FvLength
)) {
163 return EFI_OUT_OF_RESOURCES
;
167 // Data Pointer should point to the actual Address where data is to be
171 VolatileBase
= (VARIABLE_STORE_HEADER
*) ((UINTN
) mVariableModuleGlobal
->VariableGlobal
.VolatileVariableBase
);
173 DataPtr
+= mVariableModuleGlobal
->VariableGlobal
.VolatileVariableBase
;
176 if ((DataPtr
+ DataSize
) > ((UINTN
) VolatileBase
+ VolatileBase
->Size
)) {
177 return EFI_OUT_OF_RESOURCES
;
181 // Emulated non-volatile variable mode.
184 DataPtr
+= (UINTN
) mNvVariableCache
;
187 if ((DataPtr
+ DataSize
) > ((UINTN
) mNvVariableCache
+ mNvVariableCache
->Size
)) {
188 return EFI_OUT_OF_RESOURCES
;
193 // If Volatile/Emulated Non-volatile Variable just do a simple mem copy.
195 CopyMem ((UINT8
*)(UINTN
)DataPtr
, Buffer
, DataSize
);
200 // If we are here we are dealing with Non-Volatile Variables.
202 LinearOffset
= (UINTN
) FvVolHdr
;
203 CurrWritePtr
= (UINTN
) DataPtr
;
204 CurrWriteSize
= DataSize
;
208 if (CurrWritePtr
< LinearOffset
) {
209 return EFI_INVALID_PARAMETER
;
212 for (PtrBlockMapEntry
= mNvFvHeaderCache
->BlockMap
; PtrBlockMapEntry
->NumBlocks
!= 0; PtrBlockMapEntry
++) {
213 for (BlockIndex2
= 0; BlockIndex2
< PtrBlockMapEntry
->NumBlocks
; BlockIndex2
++) {
215 // Check to see if the Variable Writes are spanning through multiple
218 if ((CurrWritePtr
>= LinearOffset
) && (CurrWritePtr
< LinearOffset
+ PtrBlockMapEntry
->Length
)) {
219 if ((CurrWritePtr
+ CurrWriteSize
) <= (LinearOffset
+ PtrBlockMapEntry
->Length
)) {
220 Status
= Fvb
->Write (
223 (UINTN
) (CurrWritePtr
- LinearOffset
),
229 Size
= (UINT32
) (LinearOffset
+ PtrBlockMapEntry
->Length
- CurrWritePtr
);
230 Status
= Fvb
->Write (
233 (UINTN
) (CurrWritePtr
- LinearOffset
),
237 if (EFI_ERROR (Status
)) {
241 CurrWritePtr
= LinearOffset
+ PtrBlockMapEntry
->Length
;
242 CurrBuffer
= CurrBuffer
+ Size
;
243 CurrWriteSize
= CurrWriteSize
- Size
;
247 LinearOffset
+= PtrBlockMapEntry
->Length
;
256 Record variable error flag.
258 @param[in] Flag Variable error flag to record.
259 @param[in] VariableName Name of variable.
260 @param[in] VendorGuid Guid of variable.
261 @param[in] Attributes Attributes of the variable.
262 @param[in] VariableSize Size of the variable.
267 IN VAR_ERROR_FLAG Flag
,
268 IN CHAR16
*VariableName
,
269 IN EFI_GUID
*VendorGuid
,
270 IN UINT32 Attributes
,
271 IN UINTN VariableSize
275 VARIABLE_POINTER_TRACK Variable
;
276 VAR_ERROR_FLAG
*VarErrFlag
;
277 VAR_ERROR_FLAG TempFlag
;
280 DEBUG ((EFI_D_ERROR
, "RecordVarErrorFlag (0x%02x) %s:%g - 0x%08x - 0x%x\n", Flag
, VariableName
, VendorGuid
, Attributes
, VariableSize
));
281 if (Flag
== VAR_ERROR_FLAG_SYSTEM_ERROR
) {
283 DEBUG ((EFI_D_ERROR
, "CommonRuntimeVariableSpace = 0x%x - CommonVariableTotalSize = 0x%x\n", mVariableModuleGlobal
->CommonRuntimeVariableSpace
, mVariableModuleGlobal
->CommonVariableTotalSize
));
285 DEBUG ((EFI_D_ERROR
, "CommonVariableSpace = 0x%x - CommonVariableTotalSize = 0x%x\n", mVariableModuleGlobal
->CommonVariableSpace
, mVariableModuleGlobal
->CommonVariableTotalSize
));
288 DEBUG ((EFI_D_ERROR
, "CommonMaxUserVariableSpace = 0x%x - CommonUserVariableTotalSize = 0x%x\n", mVariableModuleGlobal
->CommonMaxUserVariableSpace
, mVariableModuleGlobal
->CommonUserVariableTotalSize
));
294 // Before EndOfDxe, just record the current boot variable error flag to local variable,
295 // and leave the variable error flag in NV flash as the last boot variable error flag.
296 // After EndOfDxe in InitializeVarErrorFlag (), the variable error flag in NV flash
297 // will be initialized to this local current boot variable error flag.
299 mCurrentBootVarErrFlag
&= Flag
;
304 // Record error flag (it should have be initialized).
306 Status
= FindVariable (
308 &gEdkiiVarErrorFlagGuid
,
310 &mVariableModuleGlobal
->VariableGlobal
,
313 if (!EFI_ERROR (Status
)) {
314 VarErrFlag
= (VAR_ERROR_FLAG
*) GetVariableDataPtr (Variable
.CurrPtr
);
315 TempFlag
= *VarErrFlag
;
317 if (TempFlag
== *VarErrFlag
) {
320 Status
= UpdateVariableStore (
321 &mVariableModuleGlobal
->VariableGlobal
,
324 mVariableModuleGlobal
->FvbInstance
,
325 (UINTN
) VarErrFlag
- (UINTN
) mNvVariableCache
+ (UINTN
) mVariableModuleGlobal
->VariableGlobal
.NonVolatileVariableBase
,
329 if (!EFI_ERROR (Status
)) {
331 // Update the data in NV cache.
333 *VarErrFlag
= TempFlag
;
339 Initialize variable error flag.
341 Before EndOfDxe, the variable indicates the last boot variable error flag,
342 then it means the last boot variable error flag must be got before EndOfDxe.
343 After EndOfDxe, the variable indicates the current boot variable error flag,
344 then it means the current boot variable error flag must be got after EndOfDxe.
348 InitializeVarErrorFlag (
353 VARIABLE_POINTER_TRACK Variable
;
355 VAR_ERROR_FLAG VarErrFlag
;
361 Flag
= mCurrentBootVarErrFlag
;
362 DEBUG ((EFI_D_INFO
, "Initialize variable error flag (%02x)\n", Flag
));
364 Status
= FindVariable (
366 &gEdkiiVarErrorFlagGuid
,
368 &mVariableModuleGlobal
->VariableGlobal
,
371 if (!EFI_ERROR (Status
)) {
372 VarErrFlag
= *((VAR_ERROR_FLAG
*) GetVariableDataPtr (Variable
.CurrPtr
));
373 if (VarErrFlag
== Flag
) {
380 &gEdkiiVarErrorFlagGuid
,
383 VARIABLE_ATTRIBUTE_NV_BS_RT
,
394 @param[in] Variable Pointer to variable header.
396 @retval TRUE User variable.
397 @retval FALSE System variable.
402 IN VARIABLE_HEADER
*Variable
405 VAR_CHECK_VARIABLE_PROPERTY Property
;
408 // Only after End Of Dxe, the variables belong to system variable are fixed.
409 // If PcdMaxUserNvStorageVariableSize is 0, it means user variable share the same NV storage with system variable,
410 // then no need to check if the variable is user variable or not specially.
412 if (mEndOfDxe
&& (mVariableModuleGlobal
->CommonMaxUserVariableSpace
!= mVariableModuleGlobal
->CommonVariableSpace
)) {
413 if (VarCheckLibVariablePropertyGet (GetVariableNamePtr (Variable
), GetVendorGuidPtr (Variable
), &Property
) == EFI_NOT_FOUND
) {
421 Calculate common user variable total size.
425 CalculateCommonUserVariableTotalSize (
429 VARIABLE_HEADER
*Variable
;
430 VARIABLE_HEADER
*NextVariable
;
432 VAR_CHECK_VARIABLE_PROPERTY Property
;
435 // Only after End Of Dxe, the variables belong to system variable are fixed.
436 // If PcdMaxUserNvStorageVariableSize is 0, it means user variable share the same NV storage with system variable,
437 // then no need to calculate the common user variable total size specially.
439 if (mEndOfDxe
&& (mVariableModuleGlobal
->CommonMaxUserVariableSpace
!= mVariableModuleGlobal
->CommonVariableSpace
)) {
440 Variable
= GetStartPointer (mNvVariableCache
);
441 while (IsValidVariableHeader (Variable
, GetEndPointer (mNvVariableCache
))) {
442 NextVariable
= GetNextVariablePtr (Variable
);
443 VariableSize
= (UINTN
) NextVariable
- (UINTN
) Variable
;
444 if ((Variable
->Attributes
& EFI_VARIABLE_HARDWARE_ERROR_RECORD
) != EFI_VARIABLE_HARDWARE_ERROR_RECORD
) {
445 if (VarCheckLibVariablePropertyGet (GetVariableNamePtr (Variable
), GetVendorGuidPtr (Variable
), &Property
) == EFI_NOT_FOUND
) {
447 // No property, it is user variable.
449 mVariableModuleGlobal
->CommonUserVariableTotalSize
+= VariableSize
;
453 Variable
= NextVariable
;
459 Initialize variable quota.
463 InitializeVariableQuota (
471 InitializeVarErrorFlag ();
472 CalculateCommonUserVariableTotalSize ();
477 Variable store garbage collection and reclaim operation.
479 @param[in] VariableBase Base address of variable store.
480 @param[out] LastVariableOffset Offset of last variable.
481 @param[in] IsVolatile The variable store is volatile or not;
482 if it is non-volatile, need FTW.
483 @param[in, out] UpdatingPtrTrack Pointer to updating variable pointer track structure.
484 @param[in] NewVariable Pointer to new variable.
485 @param[in] NewVariableSize New variable size.
487 @return EFI_SUCCESS Reclaim operation has finished successfully.
488 @return EFI_OUT_OF_RESOURCES No enough memory resources or variable space.
489 @return Others Unexpect error happened during reclaim operation.
494 IN EFI_PHYSICAL_ADDRESS VariableBase
,
495 OUT UINTN
*LastVariableOffset
,
496 IN BOOLEAN IsVolatile
,
497 IN OUT VARIABLE_POINTER_TRACK
*UpdatingPtrTrack
,
498 IN VARIABLE_HEADER
*NewVariable
,
499 IN UINTN NewVariableSize
502 VARIABLE_HEADER
*Variable
;
503 VARIABLE_HEADER
*AddedVariable
;
504 VARIABLE_HEADER
*NextVariable
;
505 VARIABLE_HEADER
*NextAddedVariable
;
506 VARIABLE_STORE_HEADER
*VariableStoreHeader
;
508 UINTN MaximumBufferSize
;
516 UINTN CommonVariableTotalSize
;
517 UINTN CommonUserVariableTotalSize
;
518 UINTN HwErrVariableTotalSize
;
519 VARIABLE_HEADER
*UpdatingVariable
;
520 VARIABLE_HEADER
*UpdatingInDeletedTransition
;
522 UpdatingVariable
= NULL
;
523 UpdatingInDeletedTransition
= NULL
;
524 if (UpdatingPtrTrack
!= NULL
) {
525 UpdatingVariable
= UpdatingPtrTrack
->CurrPtr
;
526 UpdatingInDeletedTransition
= UpdatingPtrTrack
->InDeletedTransitionPtr
;
529 VariableStoreHeader
= (VARIABLE_STORE_HEADER
*) ((UINTN
) VariableBase
);
531 CommonVariableTotalSize
= 0;
532 CommonUserVariableTotalSize
= 0;
533 HwErrVariableTotalSize
= 0;
535 if (IsVolatile
|| mVariableModuleGlobal
->VariableGlobal
.EmuNvMode
) {
537 // Start Pointers for the variable.
539 Variable
= GetStartPointer (VariableStoreHeader
);
540 MaximumBufferSize
= sizeof (VARIABLE_STORE_HEADER
);
542 while (IsValidVariableHeader (Variable
, GetEndPointer (VariableStoreHeader
))) {
543 NextVariable
= GetNextVariablePtr (Variable
);
544 if ((Variable
->State
== VAR_ADDED
|| Variable
->State
== (VAR_IN_DELETED_TRANSITION
& VAR_ADDED
)) &&
545 Variable
!= UpdatingVariable
&&
546 Variable
!= UpdatingInDeletedTransition
548 VariableSize
= (UINTN
) NextVariable
- (UINTN
) Variable
;
549 MaximumBufferSize
+= VariableSize
;
552 Variable
= NextVariable
;
555 if (NewVariable
!= NULL
) {
557 // Add the new variable size.
559 MaximumBufferSize
+= NewVariableSize
;
563 // Reserve the 1 Bytes with Oxff to identify the
564 // end of the variable buffer.
566 MaximumBufferSize
+= 1;
567 ValidBuffer
= AllocatePool (MaximumBufferSize
);
568 if (ValidBuffer
== NULL
) {
569 return EFI_OUT_OF_RESOURCES
;
573 // For NV variable reclaim, don't allocate pool here and just use mNvVariableCache
574 // as the buffer to reduce SMRAM consumption for SMM variable driver.
576 MaximumBufferSize
= mNvVariableCache
->Size
;
577 ValidBuffer
= (UINT8
*) mNvVariableCache
;
580 SetMem (ValidBuffer
, MaximumBufferSize
, 0xff);
583 // Copy variable store header.
585 CopyMem (ValidBuffer
, VariableStoreHeader
, sizeof (VARIABLE_STORE_HEADER
));
586 CurrPtr
= (UINT8
*) GetStartPointer ((VARIABLE_STORE_HEADER
*) ValidBuffer
);
589 // Reinstall all ADDED variables as long as they are not identical to Updating Variable.
591 Variable
= GetStartPointer (VariableStoreHeader
);
592 while (IsValidVariableHeader (Variable
, GetEndPointer (VariableStoreHeader
))) {
593 NextVariable
= GetNextVariablePtr (Variable
);
594 if (Variable
!= UpdatingVariable
&& Variable
->State
== VAR_ADDED
) {
595 VariableSize
= (UINTN
) NextVariable
- (UINTN
) Variable
;
596 CopyMem (CurrPtr
, (UINT8
*) Variable
, VariableSize
);
597 CurrPtr
+= VariableSize
;
598 if ((!IsVolatile
) && ((Variable
->Attributes
& EFI_VARIABLE_HARDWARE_ERROR_RECORD
) == EFI_VARIABLE_HARDWARE_ERROR_RECORD
)) {
599 HwErrVariableTotalSize
+= VariableSize
;
600 } else if ((!IsVolatile
) && ((Variable
->Attributes
& EFI_VARIABLE_HARDWARE_ERROR_RECORD
) != EFI_VARIABLE_HARDWARE_ERROR_RECORD
)) {
601 CommonVariableTotalSize
+= VariableSize
;
602 if (IsUserVariable (Variable
)) {
603 CommonUserVariableTotalSize
+= VariableSize
;
607 Variable
= NextVariable
;
611 // Reinstall all in delete transition variables.
613 Variable
= GetStartPointer (VariableStoreHeader
);
614 while (IsValidVariableHeader (Variable
, GetEndPointer (VariableStoreHeader
))) {
615 NextVariable
= GetNextVariablePtr (Variable
);
616 if (Variable
!= UpdatingVariable
&& Variable
!= UpdatingInDeletedTransition
&& Variable
->State
== (VAR_IN_DELETED_TRANSITION
& VAR_ADDED
)) {
619 // Buffer has cached all ADDED variable.
620 // Per IN_DELETED variable, we have to guarantee that
621 // no ADDED one in previous buffer.
625 AddedVariable
= GetStartPointer ((VARIABLE_STORE_HEADER
*) ValidBuffer
);
626 while (IsValidVariableHeader (AddedVariable
, GetEndPointer ((VARIABLE_STORE_HEADER
*) ValidBuffer
))) {
627 NextAddedVariable
= GetNextVariablePtr (AddedVariable
);
628 NameSize
= NameSizeOfVariable (AddedVariable
);
629 if (CompareGuid (GetVendorGuidPtr (AddedVariable
), GetVendorGuidPtr (Variable
)) &&
630 NameSize
== NameSizeOfVariable (Variable
)
632 Point0
= (VOID
*) GetVariableNamePtr (AddedVariable
);
633 Point1
= (VOID
*) GetVariableNamePtr (Variable
);
634 if (CompareMem (Point0
, Point1
, NameSize
) == 0) {
639 AddedVariable
= NextAddedVariable
;
643 // Promote VAR_IN_DELETED_TRANSITION to VAR_ADDED.
645 VariableSize
= (UINTN
) NextVariable
- (UINTN
) Variable
;
646 CopyMem (CurrPtr
, (UINT8
*) Variable
, VariableSize
);
647 ((VARIABLE_HEADER
*) CurrPtr
)->State
= VAR_ADDED
;
648 CurrPtr
+= VariableSize
;
649 if ((!IsVolatile
) && ((Variable
->Attributes
& EFI_VARIABLE_HARDWARE_ERROR_RECORD
) == EFI_VARIABLE_HARDWARE_ERROR_RECORD
)) {
650 HwErrVariableTotalSize
+= VariableSize
;
651 } else if ((!IsVolatile
) && ((Variable
->Attributes
& EFI_VARIABLE_HARDWARE_ERROR_RECORD
) != EFI_VARIABLE_HARDWARE_ERROR_RECORD
)) {
652 CommonVariableTotalSize
+= VariableSize
;
653 if (IsUserVariable (Variable
)) {
654 CommonUserVariableTotalSize
+= VariableSize
;
660 Variable
= NextVariable
;
664 // Install the new variable if it is not NULL.
666 if (NewVariable
!= NULL
) {
667 if (((UINTN
) CurrPtr
- (UINTN
) ValidBuffer
) + NewVariableSize
> VariableStoreHeader
->Size
) {
669 // No enough space to store the new variable.
671 Status
= EFI_OUT_OF_RESOURCES
;
675 if ((NewVariable
->Attributes
& EFI_VARIABLE_HARDWARE_ERROR_RECORD
) == EFI_VARIABLE_HARDWARE_ERROR_RECORD
) {
676 HwErrVariableTotalSize
+= NewVariableSize
;
677 } else if ((NewVariable
->Attributes
& EFI_VARIABLE_HARDWARE_ERROR_RECORD
) != EFI_VARIABLE_HARDWARE_ERROR_RECORD
) {
678 CommonVariableTotalSize
+= NewVariableSize
;
679 if (IsUserVariable (NewVariable
)) {
680 CommonUserVariableTotalSize
+= NewVariableSize
;
683 if ((HwErrVariableTotalSize
> PcdGet32 (PcdHwErrStorageSize
)) ||
684 (CommonVariableTotalSize
> mVariableModuleGlobal
->CommonVariableSpace
) ||
685 (CommonUserVariableTotalSize
> mVariableModuleGlobal
->CommonMaxUserVariableSpace
)) {
687 // No enough space to store the new variable by NV or NV+HR attribute.
689 Status
= EFI_OUT_OF_RESOURCES
;
694 CopyMem (CurrPtr
, (UINT8
*) NewVariable
, NewVariableSize
);
695 ((VARIABLE_HEADER
*) CurrPtr
)->State
= VAR_ADDED
;
696 if (UpdatingVariable
!= NULL
) {
697 UpdatingPtrTrack
->CurrPtr
= (VARIABLE_HEADER
*)((UINTN
)UpdatingPtrTrack
->StartPtr
+ ((UINTN
)CurrPtr
- (UINTN
)GetStartPointer ((VARIABLE_STORE_HEADER
*) ValidBuffer
)));
698 UpdatingPtrTrack
->InDeletedTransitionPtr
= NULL
;
700 CurrPtr
+= NewVariableSize
;
703 if (IsVolatile
|| mVariableModuleGlobal
->VariableGlobal
.EmuNvMode
) {
705 // If volatile/emulated non-volatile variable store, just copy valid buffer.
707 SetMem ((UINT8
*) (UINTN
) VariableBase
, VariableStoreHeader
->Size
, 0xff);
708 CopyMem ((UINT8
*) (UINTN
) VariableBase
, ValidBuffer
, (UINTN
) CurrPtr
- (UINTN
) ValidBuffer
);
709 *LastVariableOffset
= (UINTN
) CurrPtr
- (UINTN
) ValidBuffer
;
712 // Emulated non-volatile variable mode.
714 mVariableModuleGlobal
->HwErrVariableTotalSize
= HwErrVariableTotalSize
;
715 mVariableModuleGlobal
->CommonVariableTotalSize
= CommonVariableTotalSize
;
716 mVariableModuleGlobal
->CommonUserVariableTotalSize
= CommonUserVariableTotalSize
;
718 Status
= EFI_SUCCESS
;
721 // If non-volatile variable store, perform FTW here.
723 Status
= FtwVariableSpace (
725 (VARIABLE_STORE_HEADER
*) ValidBuffer
727 if (!EFI_ERROR (Status
)) {
728 *LastVariableOffset
= (UINTN
) CurrPtr
- (UINTN
) ValidBuffer
;
729 mVariableModuleGlobal
->HwErrVariableTotalSize
= HwErrVariableTotalSize
;
730 mVariableModuleGlobal
->CommonVariableTotalSize
= CommonVariableTotalSize
;
731 mVariableModuleGlobal
->CommonUserVariableTotalSize
= CommonUserVariableTotalSize
;
733 mVariableModuleGlobal
->HwErrVariableTotalSize
= 0;
734 mVariableModuleGlobal
->CommonVariableTotalSize
= 0;
735 mVariableModuleGlobal
->CommonUserVariableTotalSize
= 0;
736 Variable
= GetStartPointer ((VARIABLE_STORE_HEADER
*)(UINTN
)VariableBase
);
737 while (IsValidVariableHeader (Variable
, GetEndPointer ((VARIABLE_STORE_HEADER
*)(UINTN
)VariableBase
))) {
738 NextVariable
= GetNextVariablePtr (Variable
);
739 VariableSize
= (UINTN
) NextVariable
- (UINTN
) Variable
;
740 if ((Variable
->Attributes
& EFI_VARIABLE_HARDWARE_ERROR_RECORD
) == EFI_VARIABLE_HARDWARE_ERROR_RECORD
) {
741 mVariableModuleGlobal
->HwErrVariableTotalSize
+= VariableSize
;
742 } else if ((Variable
->Attributes
& EFI_VARIABLE_HARDWARE_ERROR_RECORD
) != EFI_VARIABLE_HARDWARE_ERROR_RECORD
) {
743 mVariableModuleGlobal
->CommonVariableTotalSize
+= VariableSize
;
744 if (IsUserVariable (Variable
)) {
745 mVariableModuleGlobal
->CommonUserVariableTotalSize
+= VariableSize
;
749 Variable
= NextVariable
;
751 *LastVariableOffset
= (UINTN
) Variable
- (UINTN
) VariableBase
;
756 if (IsVolatile
|| mVariableModuleGlobal
->VariableGlobal
.EmuNvMode
) {
757 FreePool (ValidBuffer
);
760 // For NV variable reclaim, we use mNvVariableCache as the buffer, so copy the data back.
762 CopyMem (mNvVariableCache
, (UINT8
*)(UINTN
)VariableBase
, VariableStoreHeader
->Size
);
769 Finds variable in storage blocks of volatile and non-volatile storage areas.
771 This code finds variable in storage blocks of volatile and non-volatile storage areas.
772 If VariableName is an empty string, then we just return the first
773 qualified variable without comparing VariableName and VendorGuid.
774 If IgnoreRtCheck is TRUE, then we ignore the EFI_VARIABLE_RUNTIME_ACCESS attribute check
775 at runtime when searching existing variable, only VariableName and VendorGuid are compared.
776 Otherwise, variables without EFI_VARIABLE_RUNTIME_ACCESS are not visible at runtime.
778 @param[in] VariableName Name of the variable to be found.
779 @param[in] VendorGuid Vendor GUID to be found.
780 @param[out] PtrTrack VARIABLE_POINTER_TRACK structure for output,
781 including the range searched and the target position.
782 @param[in] Global Pointer to VARIABLE_GLOBAL structure, including
783 base of volatile variable storage area, base of
784 NV variable storage area, and a lock.
785 @param[in] IgnoreRtCheck Ignore EFI_VARIABLE_RUNTIME_ACCESS attribute
786 check at runtime when searching variable.
788 @retval EFI_INVALID_PARAMETER If VariableName is not an empty string, while
790 @retval EFI_SUCCESS Variable successfully found.
791 @retval EFI_NOT_FOUND Variable not found
796 IN CHAR16
*VariableName
,
797 IN EFI_GUID
*VendorGuid
,
798 OUT VARIABLE_POINTER_TRACK
*PtrTrack
,
799 IN VARIABLE_GLOBAL
*Global
,
800 IN BOOLEAN IgnoreRtCheck
804 VARIABLE_STORE_HEADER
*VariableStoreHeader
[VariableStoreTypeMax
];
805 VARIABLE_STORE_TYPE Type
;
807 if (VariableName
[0] != 0 && VendorGuid
== NULL
) {
808 return EFI_INVALID_PARAMETER
;
812 // 0: Volatile, 1: HOB, 2: Non-Volatile.
813 // The index and attributes mapping must be kept in this order as RuntimeServiceGetNextVariableName
814 // make use of this mapping to implement search algorithm.
816 VariableStoreHeader
[VariableStoreTypeVolatile
] = (VARIABLE_STORE_HEADER
*) (UINTN
) Global
->VolatileVariableBase
;
817 VariableStoreHeader
[VariableStoreTypeHob
] = (VARIABLE_STORE_HEADER
*) (UINTN
) Global
->HobVariableBase
;
818 VariableStoreHeader
[VariableStoreTypeNv
] = mNvVariableCache
;
821 // Find the variable by walk through HOB, volatile and non-volatile variable store.
823 for (Type
= (VARIABLE_STORE_TYPE
) 0; Type
< VariableStoreTypeMax
; Type
++) {
824 if (VariableStoreHeader
[Type
] == NULL
) {
828 PtrTrack
->StartPtr
= GetStartPointer (VariableStoreHeader
[Type
]);
829 PtrTrack
->EndPtr
= GetEndPointer (VariableStoreHeader
[Type
]);
830 PtrTrack
->Volatile
= (BOOLEAN
) (Type
== VariableStoreTypeVolatile
);
832 Status
= FindVariableEx (VariableName
, VendorGuid
, IgnoreRtCheck
, PtrTrack
);
833 if (!EFI_ERROR (Status
)) {
837 return EFI_NOT_FOUND
;
841 Get index from supported language codes according to language string.
843 This code is used to get corresponding index in supported language codes. It can handle
844 RFC4646 and ISO639 language tags.
845 In ISO639 language tags, take 3-characters as a delimitation to find matched string and calculate the index.
846 In RFC4646 language tags, take semicolon as a delimitation to find matched string and calculate the index.
849 SupportedLang = "engfraengfra"
851 Iso639Language = TRUE
852 The return value is "0".
854 SupportedLang = "en;fr;en-US;fr-FR"
856 Iso639Language = FALSE
857 The return value is "3".
859 @param SupportedLang Platform supported language codes.
860 @param Lang Configured language.
861 @param Iso639Language A bool value to signify if the handler is operated on ISO639 or RFC4646.
863 @retval The index of language in the language codes.
867 GetIndexFromSupportedLangCodes(
868 IN CHAR8
*SupportedLang
,
870 IN BOOLEAN Iso639Language
875 UINTN LanguageLength
;
877 if (Iso639Language
) {
878 CompareLength
= ISO_639_2_ENTRY_SIZE
;
879 for (Index
= 0; Index
< AsciiStrLen (SupportedLang
); Index
+= CompareLength
) {
880 if (AsciiStrnCmp (Lang
, SupportedLang
+ Index
, CompareLength
) == 0) {
882 // Successfully find the index of Lang string in SupportedLang string.
884 Index
= Index
/ CompareLength
;
892 // Compare RFC4646 language code
895 for (LanguageLength
= 0; Lang
[LanguageLength
] != '\0'; LanguageLength
++);
897 for (Index
= 0; *SupportedLang
!= '\0'; Index
++, SupportedLang
+= CompareLength
) {
899 // Skip ';' characters in SupportedLang
901 for (; *SupportedLang
!= '\0' && *SupportedLang
== ';'; SupportedLang
++);
903 // Determine the length of the next language code in SupportedLang
905 for (CompareLength
= 0; SupportedLang
[CompareLength
] != '\0' && SupportedLang
[CompareLength
] != ';'; CompareLength
++);
907 if ((CompareLength
== LanguageLength
) &&
908 (AsciiStrnCmp (Lang
, SupportedLang
, CompareLength
) == 0)) {
910 // Successfully find the index of Lang string in SupportedLang string.
921 Get language string from supported language codes according to index.
923 This code is used to get corresponding language strings in supported language codes. It can handle
924 RFC4646 and ISO639 language tags.
925 In ISO639 language tags, take 3-characters as a delimitation. Find language string according to the index.
926 In RFC4646 language tags, take semicolon as a delimitation. Find language string according to the index.
929 SupportedLang = "engfraengfra"
931 Iso639Language = TRUE
932 The return value is "fra".
934 SupportedLang = "en;fr;en-US;fr-FR"
936 Iso639Language = FALSE
937 The return value is "fr".
939 @param SupportedLang Platform supported language codes.
940 @param Index The index in supported language codes.
941 @param Iso639Language A bool value to signify if the handler is operated on ISO639 or RFC4646.
943 @retval The language string in the language codes.
947 GetLangFromSupportedLangCodes (
948 IN CHAR8
*SupportedLang
,
950 IN BOOLEAN Iso639Language
958 Supported
= SupportedLang
;
959 if (Iso639Language
) {
961 // According to the index of Lang string in SupportedLang string to get the language.
962 // This code will be invoked in RUNTIME, therefore there is not a memory allocate/free operation.
963 // In driver entry, it pre-allocates a runtime attribute memory to accommodate this string.
965 CompareLength
= ISO_639_2_ENTRY_SIZE
;
966 mVariableModuleGlobal
->Lang
[CompareLength
] = '\0';
967 return CopyMem (mVariableModuleGlobal
->Lang
, SupportedLang
+ Index
* CompareLength
, CompareLength
);
972 // Take semicolon as delimitation, sequentially traverse supported language codes.
974 for (CompareLength
= 0; *Supported
!= ';' && *Supported
!= '\0'; CompareLength
++) {
977 if ((*Supported
== '\0') && (SubIndex
!= Index
)) {
979 // Have completed the traverse, but not find corrsponding string.
980 // This case is not allowed to happen.
985 if (SubIndex
== Index
) {
987 // According to the index of Lang string in SupportedLang string to get the language.
988 // As this code will be invoked in RUNTIME, therefore there is not memory allocate/free operation.
989 // In driver entry, it pre-allocates a runtime attribute memory to accommodate this string.
991 mVariableModuleGlobal
->PlatformLang
[CompareLength
] = '\0';
992 return CopyMem (mVariableModuleGlobal
->PlatformLang
, Supported
- CompareLength
, CompareLength
);
997 // Skip ';' characters in Supported
999 for (; *Supported
!= '\0' && *Supported
== ';'; Supported
++);
1005 Returns a pointer to an allocated buffer that contains the best matching language
1006 from a set of supported languages.
1008 This function supports both ISO 639-2 and RFC 4646 language codes, but language
1009 code types may not be mixed in a single call to this function. This function
1010 supports a variable argument list that allows the caller to pass in a prioritized
1011 list of language codes to test against all the language codes in SupportedLanguages.
1013 If SupportedLanguages is NULL, then ASSERT().
1015 @param[in] SupportedLanguages A pointer to a Null-terminated ASCII string that
1016 contains a set of language codes in the format
1017 specified by Iso639Language.
1018 @param[in] Iso639Language If not zero, then all language codes are assumed to be
1019 in ISO 639-2 format. If zero, then all language
1020 codes are assumed to be in RFC 4646 language format
1021 @param[in] ... A variable argument list that contains pointers to
1022 Null-terminated ASCII strings that contain one or more
1023 language codes in the format specified by Iso639Language.
1024 The first language code from each of these language
1025 code lists is used to determine if it is an exact or
1026 close match to any of the language codes in
1027 SupportedLanguages. Close matches only apply to RFC 4646
1028 language codes, and the matching algorithm from RFC 4647
1029 is used to determine if a close match is present. If
1030 an exact or close match is found, then the matching
1031 language code from SupportedLanguages is returned. If
1032 no matches are found, then the next variable argument
1033 parameter is evaluated. The variable argument list
1034 is terminated by a NULL.
1036 @retval NULL The best matching language could not be found in SupportedLanguages.
1037 @retval NULL There are not enough resources available to return the best matching
1039 @retval Other A pointer to a Null-terminated ASCII string that is the best matching
1040 language in SupportedLanguages.
1045 VariableGetBestLanguage (
1046 IN CONST CHAR8
*SupportedLanguages
,
1047 IN UINTN Iso639Language
,
1053 UINTN CompareLength
;
1054 UINTN LanguageLength
;
1055 CONST CHAR8
*Supported
;
1058 if (SupportedLanguages
== NULL
) {
1062 VA_START (Args
, Iso639Language
);
1063 while ((Language
= VA_ARG (Args
, CHAR8
*)) != NULL
) {
1065 // Default to ISO 639-2 mode
1068 LanguageLength
= MIN (3, AsciiStrLen (Language
));
1071 // If in RFC 4646 mode, then determine the length of the first RFC 4646 language code in Language
1073 if (Iso639Language
== 0) {
1074 for (LanguageLength
= 0; Language
[LanguageLength
] != 0 && Language
[LanguageLength
] != ';'; LanguageLength
++);
1078 // Trim back the length of Language used until it is empty
1080 while (LanguageLength
> 0) {
1082 // Loop through all language codes in SupportedLanguages
1084 for (Supported
= SupportedLanguages
; *Supported
!= '\0'; Supported
+= CompareLength
) {
1086 // In RFC 4646 mode, then Loop through all language codes in SupportedLanguages
1088 if (Iso639Language
== 0) {
1090 // Skip ';' characters in Supported
1092 for (; *Supported
!= '\0' && *Supported
== ';'; Supported
++);
1094 // Determine the length of the next language code in Supported
1096 for (CompareLength
= 0; Supported
[CompareLength
] != 0 && Supported
[CompareLength
] != ';'; CompareLength
++);
1098 // If Language is longer than the Supported, then skip to the next language
1100 if (LanguageLength
> CompareLength
) {
1105 // See if the first LanguageLength characters in Supported match Language
1107 if (AsciiStrnCmp (Supported
, Language
, LanguageLength
) == 0) {
1110 Buffer
= (Iso639Language
!= 0) ? mVariableModuleGlobal
->Lang
: mVariableModuleGlobal
->PlatformLang
;
1111 Buffer
[CompareLength
] = '\0';
1112 return CopyMem (Buffer
, Supported
, CompareLength
);
1116 if (Iso639Language
!= 0) {
1118 // If ISO 639 mode, then each language can only be tested once
1123 // If RFC 4646 mode, then trim Language from the right to the next '-' character
1125 for (LanguageLength
--; LanguageLength
> 0 && Language
[LanguageLength
] != '-'; LanguageLength
--);
1132 // No matches were found
1138 This function is to check if the remaining variable space is enough to set
1139 all Variables from argument list successfully. The purpose of the check
1140 is to keep the consistency of the Variables to be in variable storage.
1142 Note: Variables are assumed to be in same storage.
1143 The set sequence of Variables will be same with the sequence of VariableEntry from argument list,
1144 so follow the argument sequence to check the Variables.
1146 @param[in] Attributes Variable attributes for Variable entries.
1147 @param[in] Marker VA_LIST style variable argument list.
1148 The variable argument list with type VARIABLE_ENTRY_CONSISTENCY *.
1149 A NULL terminates the list. The VariableSize of
1150 VARIABLE_ENTRY_CONSISTENCY is the variable data size as input.
1151 It will be changed to variable total size as output.
1153 @retval TRUE Have enough variable space to set the Variables successfully.
1154 @retval FALSE No enough variable space to set the Variables successfully.
1159 CheckRemainingSpaceForConsistencyInternal (
1160 IN UINT32 Attributes
,
1166 VARIABLE_ENTRY_CONSISTENCY
*VariableEntry
;
1167 UINT64 MaximumVariableStorageSize
;
1168 UINT64 RemainingVariableStorageSize
;
1169 UINT64 MaximumVariableSize
;
1170 UINTN TotalNeededSize
;
1171 UINTN OriginalVarSize
;
1172 VARIABLE_STORE_HEADER
*VariableStoreHeader
;
1173 VARIABLE_POINTER_TRACK VariablePtrTrack
;
1174 VARIABLE_HEADER
*NextVariable
;
1179 // Non-Volatile related.
1181 VariableStoreHeader
= mNvVariableCache
;
1183 Status
= VariableServiceQueryVariableInfoInternal (
1185 &MaximumVariableStorageSize
,
1186 &RemainingVariableStorageSize
,
1187 &MaximumVariableSize
1189 ASSERT_EFI_ERROR (Status
);
1191 TotalNeededSize
= 0;
1192 VA_COPY (Args
, Marker
);
1193 VariableEntry
= VA_ARG (Args
, VARIABLE_ENTRY_CONSISTENCY
*);
1194 while (VariableEntry
!= NULL
) {
1196 // Calculate variable total size.
1198 VarNameSize
= StrSize (VariableEntry
->Name
);
1199 VarNameSize
+= GET_PAD_SIZE (VarNameSize
);
1200 VarDataSize
= VariableEntry
->VariableSize
;
1201 VarDataSize
+= GET_PAD_SIZE (VarDataSize
);
1202 VariableEntry
->VariableSize
= HEADER_ALIGN (GetVariableHeaderSize () + VarNameSize
+ VarDataSize
);
1204 TotalNeededSize
+= VariableEntry
->VariableSize
;
1205 VariableEntry
= VA_ARG (Args
, VARIABLE_ENTRY_CONSISTENCY
*);
1209 if (RemainingVariableStorageSize
>= TotalNeededSize
) {
1211 // Already have enough space.
1214 } else if (AtRuntime ()) {
1216 // At runtime, no reclaim.
1217 // The original variable space of Variables can't be reused.
1222 VA_COPY (Args
, Marker
);
1223 VariableEntry
= VA_ARG (Args
, VARIABLE_ENTRY_CONSISTENCY
*);
1224 while (VariableEntry
!= NULL
) {
1226 // Check if Variable[Index] has been present and get its size.
1228 OriginalVarSize
= 0;
1229 VariablePtrTrack
.StartPtr
= GetStartPointer (VariableStoreHeader
);
1230 VariablePtrTrack
.EndPtr
= GetEndPointer (VariableStoreHeader
);
1231 Status
= FindVariableEx (
1232 VariableEntry
->Name
,
1233 VariableEntry
->Guid
,
1237 if (!EFI_ERROR (Status
)) {
1239 // Get size of Variable[Index].
1241 NextVariable
= GetNextVariablePtr (VariablePtrTrack
.CurrPtr
);
1242 OriginalVarSize
= (UINTN
) NextVariable
- (UINTN
) VariablePtrTrack
.CurrPtr
;
1244 // Add the original size of Variable[Index] to remaining variable storage size.
1246 RemainingVariableStorageSize
+= OriginalVarSize
;
1248 if (VariableEntry
->VariableSize
> RemainingVariableStorageSize
) {
1250 // No enough space for Variable[Index].
1256 // Sub the (new) size of Variable[Index] from remaining variable storage size.
1258 RemainingVariableStorageSize
-= VariableEntry
->VariableSize
;
1259 VariableEntry
= VA_ARG (Args
, VARIABLE_ENTRY_CONSISTENCY
*);
1267 This function is to check if the remaining variable space is enough to set
1268 all Variables from argument list successfully. The purpose of the check
1269 is to keep the consistency of the Variables to be in variable storage.
1271 Note: Variables are assumed to be in same storage.
1272 The set sequence of Variables will be same with the sequence of VariableEntry from argument list,
1273 so follow the argument sequence to check the Variables.
1275 @param[in] Attributes Variable attributes for Variable entries.
1276 @param ... The variable argument list with type VARIABLE_ENTRY_CONSISTENCY *.
1277 A NULL terminates the list. The VariableSize of
1278 VARIABLE_ENTRY_CONSISTENCY is the variable data size as input.
1279 It will be changed to variable total size as output.
1281 @retval TRUE Have enough variable space to set the Variables successfully.
1282 @retval FALSE No enough variable space to set the Variables successfully.
1287 CheckRemainingSpaceForConsistency (
1288 IN UINT32 Attributes
,
1295 VA_START (Marker
, Attributes
);
1297 Return
= CheckRemainingSpaceForConsistencyInternal (Attributes
, Marker
);
1305 Hook the operations in PlatformLangCodes, LangCodes, PlatformLang and Lang.
1307 When setting Lang/LangCodes, simultaneously update PlatformLang/PlatformLangCodes.
1309 According to UEFI spec, PlatformLangCodes/LangCodes are only set once in firmware initialization,
1310 and are read-only. Therefore, in variable driver, only store the original value for other use.
1312 @param[in] VariableName Name of variable.
1314 @param[in] Data Variable data.
1316 @param[in] DataSize Size of data. 0 means delete.
1318 @retval EFI_SUCCESS The update operation is successful or ignored.
1319 @retval EFI_WRITE_PROTECTED Update PlatformLangCodes/LangCodes at runtime.
1320 @retval EFI_OUT_OF_RESOURCES No enough variable space to do the update operation.
1321 @retval Others Other errors happened during the update operation.
1325 AutoUpdateLangVariable (
1326 IN CHAR16
*VariableName
,
1332 CHAR8
*BestPlatformLang
;
1336 VARIABLE_POINTER_TRACK Variable
;
1337 BOOLEAN SetLanguageCodes
;
1338 VARIABLE_ENTRY_CONSISTENCY VariableEntry
[2];
1341 // Don't do updates for delete operation
1343 if (DataSize
== 0) {
1347 SetLanguageCodes
= FALSE
;
1349 if (StrCmp (VariableName
, EFI_PLATFORM_LANG_CODES_VARIABLE_NAME
) == 0) {
1351 // PlatformLangCodes is a volatile variable, so it can not be updated at runtime.
1354 return EFI_WRITE_PROTECTED
;
1357 SetLanguageCodes
= TRUE
;
1360 // According to UEFI spec, PlatformLangCodes is only set once in firmware initialization, and is read-only
1361 // Therefore, in variable driver, only store the original value for other use.
1363 if (mVariableModuleGlobal
->PlatformLangCodes
!= NULL
) {
1364 FreePool (mVariableModuleGlobal
->PlatformLangCodes
);
1366 mVariableModuleGlobal
->PlatformLangCodes
= AllocateRuntimeCopyPool (DataSize
, Data
);
1367 ASSERT (mVariableModuleGlobal
->PlatformLangCodes
!= NULL
);
1370 // PlatformLang holds a single language from PlatformLangCodes,
1371 // so the size of PlatformLangCodes is enough for the PlatformLang.
1373 if (mVariableModuleGlobal
->PlatformLang
!= NULL
) {
1374 FreePool (mVariableModuleGlobal
->PlatformLang
);
1376 mVariableModuleGlobal
->PlatformLang
= AllocateRuntimePool (DataSize
);
1377 ASSERT (mVariableModuleGlobal
->PlatformLang
!= NULL
);
1379 } else if (StrCmp (VariableName
, EFI_LANG_CODES_VARIABLE_NAME
) == 0) {
1381 // LangCodes is a volatile variable, so it can not be updated at runtime.
1384 return EFI_WRITE_PROTECTED
;
1387 SetLanguageCodes
= TRUE
;
1390 // According to UEFI spec, LangCodes is only set once in firmware initialization, and is read-only
1391 // Therefore, in variable driver, only store the original value for other use.
1393 if (mVariableModuleGlobal
->LangCodes
!= NULL
) {
1394 FreePool (mVariableModuleGlobal
->LangCodes
);
1396 mVariableModuleGlobal
->LangCodes
= AllocateRuntimeCopyPool (DataSize
, Data
);
1397 ASSERT (mVariableModuleGlobal
->LangCodes
!= NULL
);
1400 if (SetLanguageCodes
1401 && (mVariableModuleGlobal
->PlatformLangCodes
!= NULL
)
1402 && (mVariableModuleGlobal
->LangCodes
!= NULL
)) {
1404 // Update Lang if PlatformLang is already set
1405 // Update PlatformLang if Lang is already set
1407 Status
= FindVariable (EFI_PLATFORM_LANG_VARIABLE_NAME
, &gEfiGlobalVariableGuid
, &Variable
, &mVariableModuleGlobal
->VariableGlobal
, FALSE
);
1408 if (!EFI_ERROR (Status
)) {
1412 VariableName
= EFI_PLATFORM_LANG_VARIABLE_NAME
;
1413 Data
= GetVariableDataPtr (Variable
.CurrPtr
);
1414 DataSize
= DataSizeOfVariable (Variable
.CurrPtr
);
1416 Status
= FindVariable (EFI_LANG_VARIABLE_NAME
, &gEfiGlobalVariableGuid
, &Variable
, &mVariableModuleGlobal
->VariableGlobal
, FALSE
);
1417 if (!EFI_ERROR (Status
)) {
1419 // Update PlatformLang
1421 VariableName
= EFI_LANG_VARIABLE_NAME
;
1422 Data
= GetVariableDataPtr (Variable
.CurrPtr
);
1423 DataSize
= DataSizeOfVariable (Variable
.CurrPtr
);
1426 // Neither PlatformLang nor Lang is set, directly return
1433 Status
= EFI_SUCCESS
;
1436 // According to UEFI spec, "Lang" and "PlatformLang" is NV|BS|RT attributions.
1438 Attributes
= EFI_VARIABLE_NON_VOLATILE
| EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_RUNTIME_ACCESS
;
1440 if (StrCmp (VariableName
, EFI_PLATFORM_LANG_VARIABLE_NAME
) == 0) {
1442 // Update Lang when PlatformLangCodes/LangCodes were set.
1444 if ((mVariableModuleGlobal
->PlatformLangCodes
!= NULL
) && (mVariableModuleGlobal
->LangCodes
!= NULL
)) {
1446 // When setting PlatformLang, firstly get most matched language string from supported language codes.
1448 BestPlatformLang
= VariableGetBestLanguage (mVariableModuleGlobal
->PlatformLangCodes
, FALSE
, Data
, NULL
);
1449 if (BestPlatformLang
!= NULL
) {
1451 // Get the corresponding index in language codes.
1453 Index
= GetIndexFromSupportedLangCodes (mVariableModuleGlobal
->PlatformLangCodes
, BestPlatformLang
, FALSE
);
1456 // Get the corresponding ISO639 language tag according to RFC4646 language tag.
1458 BestLang
= GetLangFromSupportedLangCodes (mVariableModuleGlobal
->LangCodes
, Index
, TRUE
);
1461 // Check the variable space for both Lang and PlatformLang variable.
1463 VariableEntry
[0].VariableSize
= ISO_639_2_ENTRY_SIZE
+ 1;
1464 VariableEntry
[0].Guid
= &gEfiGlobalVariableGuid
;
1465 VariableEntry
[0].Name
= EFI_LANG_VARIABLE_NAME
;
1467 VariableEntry
[1].VariableSize
= AsciiStrSize (BestPlatformLang
);
1468 VariableEntry
[1].Guid
= &gEfiGlobalVariableGuid
;
1469 VariableEntry
[1].Name
= EFI_PLATFORM_LANG_VARIABLE_NAME
;
1470 if (!CheckRemainingSpaceForConsistency (VARIABLE_ATTRIBUTE_NV_BS_RT
, &VariableEntry
[0], &VariableEntry
[1], NULL
)) {
1472 // No enough variable space to set both Lang and PlatformLang successfully.
1474 Status
= EFI_OUT_OF_RESOURCES
;
1477 // Successfully convert PlatformLang to Lang, and set the BestLang value into Lang variable simultaneously.
1479 FindVariable (EFI_LANG_VARIABLE_NAME
, &gEfiGlobalVariableGuid
, &Variable
, &mVariableModuleGlobal
->VariableGlobal
, FALSE
);
1481 Status
= UpdateVariable (EFI_LANG_VARIABLE_NAME
, &gEfiGlobalVariableGuid
, BestLang
,
1482 ISO_639_2_ENTRY_SIZE
+ 1, Attributes
, 0, 0, &Variable
, NULL
);
1485 DEBUG ((EFI_D_INFO
, "Variable Driver Auto Update PlatformLang, PlatformLang:%a, Lang:%a Status: %r\n", BestPlatformLang
, BestLang
, Status
));
1489 } else if (StrCmp (VariableName
, EFI_LANG_VARIABLE_NAME
) == 0) {
1491 // Update PlatformLang when PlatformLangCodes/LangCodes were set.
1493 if ((mVariableModuleGlobal
->PlatformLangCodes
!= NULL
) && (mVariableModuleGlobal
->LangCodes
!= NULL
)) {
1495 // When setting Lang, firstly get most matched language string from supported language codes.
1497 BestLang
= VariableGetBestLanguage (mVariableModuleGlobal
->LangCodes
, TRUE
, Data
, NULL
);
1498 if (BestLang
!= NULL
) {
1500 // Get the corresponding index in language codes.
1502 Index
= GetIndexFromSupportedLangCodes (mVariableModuleGlobal
->LangCodes
, BestLang
, TRUE
);
1505 // Get the corresponding RFC4646 language tag according to ISO639 language tag.
1507 BestPlatformLang
= GetLangFromSupportedLangCodes (mVariableModuleGlobal
->PlatformLangCodes
, Index
, FALSE
);
1510 // Check the variable space for both PlatformLang and Lang variable.
1512 VariableEntry
[0].VariableSize
= AsciiStrSize (BestPlatformLang
);
1513 VariableEntry
[0].Guid
= &gEfiGlobalVariableGuid
;
1514 VariableEntry
[0].Name
= EFI_PLATFORM_LANG_VARIABLE_NAME
;
1516 VariableEntry
[1].VariableSize
= ISO_639_2_ENTRY_SIZE
+ 1;
1517 VariableEntry
[1].Guid
= &gEfiGlobalVariableGuid
;
1518 VariableEntry
[1].Name
= EFI_LANG_VARIABLE_NAME
;
1519 if (!CheckRemainingSpaceForConsistency (VARIABLE_ATTRIBUTE_NV_BS_RT
, &VariableEntry
[0], &VariableEntry
[1], NULL
)) {
1521 // No enough variable space to set both PlatformLang and Lang successfully.
1523 Status
= EFI_OUT_OF_RESOURCES
;
1526 // Successfully convert Lang to PlatformLang, and set the BestPlatformLang value into PlatformLang variable simultaneously.
1528 FindVariable (EFI_PLATFORM_LANG_VARIABLE_NAME
, &gEfiGlobalVariableGuid
, &Variable
, &mVariableModuleGlobal
->VariableGlobal
, FALSE
);
1530 Status
= UpdateVariable (EFI_PLATFORM_LANG_VARIABLE_NAME
, &gEfiGlobalVariableGuid
, BestPlatformLang
,
1531 AsciiStrSize (BestPlatformLang
), Attributes
, 0, 0, &Variable
, NULL
);
1534 DEBUG ((EFI_D_INFO
, "Variable Driver Auto Update Lang, Lang:%a, PlatformLang:%a Status: %r\n", BestLang
, BestPlatformLang
, Status
));
1539 if (SetLanguageCodes
) {
1541 // Continue to set PlatformLangCodes or LangCodes.
1550 Update the variable region with Variable information. If EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS is set,
1551 index of associated public key is needed.
1553 @param[in] VariableName Name of variable.
1554 @param[in] VendorGuid Guid of variable.
1555 @param[in] Data Variable data.
1556 @param[in] DataSize Size of data. 0 means delete.
1557 @param[in] Attributes Attributes of the variable.
1558 @param[in] KeyIndex Index of associated public key.
1559 @param[in] MonotonicCount Value of associated monotonic count.
1560 @param[in, out] CacheVariable The variable information which is used to keep track of variable usage.
1561 @param[in] TimeStamp Value of associated TimeStamp.
1563 @retval EFI_SUCCESS The update operation is success.
1564 @retval EFI_OUT_OF_RESOURCES Variable region is full, can not write other data into this region.
1569 IN CHAR16
*VariableName
,
1570 IN EFI_GUID
*VendorGuid
,
1573 IN UINT32 Attributes OPTIONAL
,
1574 IN UINT32 KeyIndex OPTIONAL
,
1575 IN UINT64 MonotonicCount OPTIONAL
,
1576 IN OUT VARIABLE_POINTER_TRACK
*CacheVariable
,
1577 IN EFI_TIME
*TimeStamp OPTIONAL
1581 VARIABLE_HEADER
*NextVariable
;
1584 UINTN VarNameOffset
;
1585 UINTN VarDataOffset
;
1589 EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*Fvb
;
1591 VARIABLE_POINTER_TRACK
*Variable
;
1592 VARIABLE_POINTER_TRACK NvVariable
;
1593 VARIABLE_STORE_HEADER
*VariableStoreHeader
;
1594 UINT8
*BufferForMerge
;
1595 UINTN MergedBufSize
;
1598 BOOLEAN IsCommonVariable
;
1599 BOOLEAN IsCommonUserVariable
;
1600 AUTHENTICATED_VARIABLE_HEADER
*AuthVariable
;
1602 if (mVariableModuleGlobal
->FvbInstance
== NULL
&& !mVariableModuleGlobal
->VariableGlobal
.EmuNvMode
) {
1604 // The FVB protocol is not ready, so the EFI_VARIABLE_WRITE_ARCH_PROTOCOL is not installed.
1606 if ((Attributes
& EFI_VARIABLE_NON_VOLATILE
) != 0) {
1608 // Trying to update NV variable prior to the installation of EFI_VARIABLE_WRITE_ARCH_PROTOCOL
1610 DEBUG ((EFI_D_ERROR
, "Update NV variable before EFI_VARIABLE_WRITE_ARCH_PROTOCOL ready - %r\n", EFI_NOT_AVAILABLE_YET
));
1611 return EFI_NOT_AVAILABLE_YET
;
1612 } else if ((Attributes
& VARIABLE_ATTRIBUTE_AT_AW
) != 0) {
1614 // Trying to update volatile authenticated variable prior to the installation of EFI_VARIABLE_WRITE_ARCH_PROTOCOL
1615 // The authenticated variable perhaps is not initialized, just return here.
1617 DEBUG ((EFI_D_ERROR
, "Update AUTH variable before EFI_VARIABLE_WRITE_ARCH_PROTOCOL ready - %r\n", EFI_NOT_AVAILABLE_YET
));
1618 return EFI_NOT_AVAILABLE_YET
;
1623 // Check if CacheVariable points to the variable in variable HOB.
1624 // If yes, let CacheVariable points to the variable in NV variable cache.
1626 if ((CacheVariable
->CurrPtr
!= NULL
) &&
1627 (mVariableModuleGlobal
->VariableGlobal
.HobVariableBase
!= 0) &&
1628 (CacheVariable
->StartPtr
== GetStartPointer ((VARIABLE_STORE_HEADER
*) (UINTN
) mVariableModuleGlobal
->VariableGlobal
.HobVariableBase
))
1630 CacheVariable
->StartPtr
= GetStartPointer (mNvVariableCache
);
1631 CacheVariable
->EndPtr
= GetEndPointer (mNvVariableCache
);
1632 CacheVariable
->Volatile
= FALSE
;
1633 Status
= FindVariableEx (VariableName
, VendorGuid
, FALSE
, CacheVariable
);
1634 if (CacheVariable
->CurrPtr
== NULL
|| EFI_ERROR (Status
)) {
1636 // There is no matched variable in NV variable cache.
1638 if ((((Attributes
& EFI_VARIABLE_APPEND_WRITE
) == 0) && (DataSize
== 0)) || (Attributes
== 0)) {
1640 // It is to delete variable,
1641 // go to delete this variable in variable HOB and
1642 // try to flush other variables from HOB to flash.
1644 UpdateVariableInfo (VariableName
, VendorGuid
, FALSE
, FALSE
, FALSE
, TRUE
, FALSE
);
1645 FlushHobVariableToFlash (VariableName
, VendorGuid
);
1651 if ((CacheVariable
->CurrPtr
== NULL
) || CacheVariable
->Volatile
) {
1652 Variable
= CacheVariable
;
1655 // Update/Delete existing NV variable.
1656 // CacheVariable points to the variable in the memory copy of Flash area
1657 // Now let Variable points to the same variable in Flash area.
1659 VariableStoreHeader
= (VARIABLE_STORE_HEADER
*) ((UINTN
) mVariableModuleGlobal
->VariableGlobal
.NonVolatileVariableBase
);
1660 Variable
= &NvVariable
;
1661 Variable
->StartPtr
= GetStartPointer (VariableStoreHeader
);
1662 Variable
->EndPtr
= (VARIABLE_HEADER
*)((UINTN
)Variable
->StartPtr
+ ((UINTN
)CacheVariable
->EndPtr
- (UINTN
)CacheVariable
->StartPtr
));
1664 Variable
->CurrPtr
= (VARIABLE_HEADER
*)((UINTN
)Variable
->StartPtr
+ ((UINTN
)CacheVariable
->CurrPtr
- (UINTN
)CacheVariable
->StartPtr
));
1665 if (CacheVariable
->InDeletedTransitionPtr
!= NULL
) {
1666 Variable
->InDeletedTransitionPtr
= (VARIABLE_HEADER
*)((UINTN
)Variable
->StartPtr
+ ((UINTN
)CacheVariable
->InDeletedTransitionPtr
- (UINTN
)CacheVariable
->StartPtr
));
1668 Variable
->InDeletedTransitionPtr
= NULL
;
1670 Variable
->Volatile
= FALSE
;
1673 Fvb
= mVariableModuleGlobal
->FvbInstance
;
1676 // Tricky part: Use scratch data area at the end of volatile variable store
1677 // as a temporary storage.
1679 NextVariable
= GetEndPointer ((VARIABLE_STORE_HEADER
*) ((UINTN
) mVariableModuleGlobal
->VariableGlobal
.VolatileVariableBase
));
1680 ScratchSize
= mVariableModuleGlobal
->ScratchBufferSize
;
1681 SetMem (NextVariable
, ScratchSize
, 0xff);
1684 if (Variable
->CurrPtr
!= NULL
) {
1686 // Update/Delete existing variable.
1690 // If AtRuntime and the variable is Volatile and Runtime Access,
1691 // the volatile is ReadOnly, and SetVariable should be aborted and
1692 // return EFI_WRITE_PROTECTED.
1694 if (Variable
->Volatile
) {
1695 Status
= EFI_WRITE_PROTECTED
;
1699 // Only variable that have NV attributes can be updated/deleted in Runtime.
1701 if ((CacheVariable
->CurrPtr
->Attributes
& EFI_VARIABLE_NON_VOLATILE
) == 0) {
1702 Status
= EFI_INVALID_PARAMETER
;
1707 // Only variable that have RT attributes can be updated/deleted in Runtime.
1709 if ((CacheVariable
->CurrPtr
->Attributes
& EFI_VARIABLE_RUNTIME_ACCESS
) == 0) {
1710 Status
= EFI_INVALID_PARAMETER
;
1716 // Setting a data variable with no access, or zero DataSize attributes
1717 // causes it to be deleted.
1718 // When the EFI_VARIABLE_APPEND_WRITE attribute is set, DataSize of zero will
1719 // not delete the variable.
1721 if ((((Attributes
& EFI_VARIABLE_APPEND_WRITE
) == 0) && (DataSize
== 0))|| ((Attributes
& (EFI_VARIABLE_RUNTIME_ACCESS
| EFI_VARIABLE_BOOTSERVICE_ACCESS
)) == 0)) {
1722 if (Variable
->InDeletedTransitionPtr
!= NULL
) {
1724 // Both ADDED and IN_DELETED_TRANSITION variable are present,
1725 // set IN_DELETED_TRANSITION one to DELETED state first.
1727 ASSERT (CacheVariable
->InDeletedTransitionPtr
!= NULL
);
1728 State
= CacheVariable
->InDeletedTransitionPtr
->State
;
1729 State
&= VAR_DELETED
;
1730 Status
= UpdateVariableStore (
1731 &mVariableModuleGlobal
->VariableGlobal
,
1735 (UINTN
) &Variable
->InDeletedTransitionPtr
->State
,
1739 if (!EFI_ERROR (Status
)) {
1740 if (!Variable
->Volatile
) {
1741 CacheVariable
->InDeletedTransitionPtr
->State
= State
;
1748 State
= CacheVariable
->CurrPtr
->State
;
1749 State
&= VAR_DELETED
;
1751 Status
= UpdateVariableStore (
1752 &mVariableModuleGlobal
->VariableGlobal
,
1756 (UINTN
) &Variable
->CurrPtr
->State
,
1760 if (!EFI_ERROR (Status
)) {
1761 UpdateVariableInfo (VariableName
, VendorGuid
, Variable
->Volatile
, FALSE
, FALSE
, TRUE
, FALSE
);
1762 if (!Variable
->Volatile
) {
1763 CacheVariable
->CurrPtr
->State
= State
;
1764 FlushHobVariableToFlash (VariableName
, VendorGuid
);
1770 // If the variable is marked valid, and the same data has been passed in,
1771 // then return to the caller immediately.
1773 if (DataSizeOfVariable (CacheVariable
->CurrPtr
) == DataSize
&&
1774 (CompareMem (Data
, GetVariableDataPtr (CacheVariable
->CurrPtr
), DataSize
) == 0) &&
1775 ((Attributes
& EFI_VARIABLE_APPEND_WRITE
) == 0) &&
1776 (TimeStamp
== NULL
)) {
1778 // Variable content unchanged and no need to update timestamp, just return.
1780 UpdateVariableInfo (VariableName
, VendorGuid
, Variable
->Volatile
, FALSE
, TRUE
, FALSE
, FALSE
);
1781 Status
= EFI_SUCCESS
;
1783 } else if ((CacheVariable
->CurrPtr
->State
== VAR_ADDED
) ||
1784 (CacheVariable
->CurrPtr
->State
== (VAR_ADDED
& VAR_IN_DELETED_TRANSITION
))) {
1787 // EFI_VARIABLE_APPEND_WRITE attribute only effects for existing variable.
1789 if ((Attributes
& EFI_VARIABLE_APPEND_WRITE
) != 0) {
1791 // NOTE: From 0 to DataOffset of NextVariable is reserved for Variable Header and Name.
1792 // From DataOffset of NextVariable is to save the existing variable data.
1794 DataOffset
= GetVariableDataOffset (CacheVariable
->CurrPtr
);
1795 BufferForMerge
= (UINT8
*) ((UINTN
) NextVariable
+ DataOffset
);
1796 CopyMem (BufferForMerge
, (UINT8
*) ((UINTN
) CacheVariable
->CurrPtr
+ DataOffset
), DataSizeOfVariable (CacheVariable
->CurrPtr
));
1799 // Set Max Auth/Non-Volatile/Volatile Variable Data Size as default MaxDataSize.
1801 if ((Attributes
& VARIABLE_ATTRIBUTE_AT_AW
) != 0) {
1802 MaxDataSize
= mVariableModuleGlobal
->MaxAuthVariableSize
- DataOffset
;
1803 } else if ((Attributes
& EFI_VARIABLE_NON_VOLATILE
) != 0) {
1804 MaxDataSize
= mVariableModuleGlobal
->MaxVariableSize
- DataOffset
;
1806 MaxDataSize
= mVariableModuleGlobal
->MaxVolatileVariableSize
- DataOffset
;
1810 // Append the new data to the end of existing data.
1811 // Max Harware error record variable data size is different from common/auth variable.
1813 if ((Attributes
& EFI_VARIABLE_HARDWARE_ERROR_RECORD
) == EFI_VARIABLE_HARDWARE_ERROR_RECORD
) {
1814 MaxDataSize
= PcdGet32 (PcdMaxHardwareErrorVariableSize
) - DataOffset
;
1817 if (DataSizeOfVariable (CacheVariable
->CurrPtr
) + DataSize
> MaxDataSize
) {
1819 // Existing data size + new data size exceed maximum variable size limitation.
1821 Status
= EFI_INVALID_PARAMETER
;
1824 CopyMem ((UINT8
*) ((UINTN
) BufferForMerge
+ DataSizeOfVariable (CacheVariable
->CurrPtr
)), Data
, DataSize
);
1825 MergedBufSize
= DataSizeOfVariable (CacheVariable
->CurrPtr
) + DataSize
;
1828 // BufferForMerge(from DataOffset of NextVariable) has included the merged existing and new data.
1830 Data
= BufferForMerge
;
1831 DataSize
= MergedBufSize
;
1836 // Mark the old variable as in delete transition.
1838 State
= CacheVariable
->CurrPtr
->State
;
1839 State
&= VAR_IN_DELETED_TRANSITION
;
1841 Status
= UpdateVariableStore (
1842 &mVariableModuleGlobal
->VariableGlobal
,
1846 (UINTN
) &Variable
->CurrPtr
->State
,
1850 if (EFI_ERROR (Status
)) {
1853 if (!Variable
->Volatile
) {
1854 CacheVariable
->CurrPtr
->State
= State
;
1859 // Not found existing variable. Create a new variable.
1862 if ((DataSize
== 0) && ((Attributes
& EFI_VARIABLE_APPEND_WRITE
) != 0)) {
1863 Status
= EFI_SUCCESS
;
1868 // Make sure we are trying to create a new variable.
1869 // Setting a data variable with zero DataSize or no access attributes means to delete it.
1871 if (DataSize
== 0 || (Attributes
& (EFI_VARIABLE_RUNTIME_ACCESS
| EFI_VARIABLE_BOOTSERVICE_ACCESS
)) == 0) {
1872 Status
= EFI_NOT_FOUND
;
1877 // Only variable have NV|RT attribute can be created in Runtime.
1880 (((Attributes
& EFI_VARIABLE_RUNTIME_ACCESS
) == 0) || ((Attributes
& EFI_VARIABLE_NON_VOLATILE
) == 0))) {
1881 Status
= EFI_INVALID_PARAMETER
;
1887 // Function part - create a new variable and copy the data.
1888 // Both update a variable and create a variable will come here.
1890 NextVariable
->StartId
= VARIABLE_DATA
;
1892 // NextVariable->State = VAR_ADDED;
1894 NextVariable
->Reserved
= 0;
1895 if (mVariableModuleGlobal
->VariableGlobal
.AuthFormat
) {
1896 AuthVariable
= (AUTHENTICATED_VARIABLE_HEADER
*) NextVariable
;
1897 AuthVariable
->PubKeyIndex
= KeyIndex
;
1898 AuthVariable
->MonotonicCount
= MonotonicCount
;
1899 ZeroMem (&AuthVariable
->TimeStamp
, sizeof (EFI_TIME
));
1901 if (((Attributes
& EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS
) != 0) &&
1902 (TimeStamp
!= NULL
)) {
1903 if ((Attributes
& EFI_VARIABLE_APPEND_WRITE
) == 0) {
1904 CopyMem (&AuthVariable
->TimeStamp
, TimeStamp
, sizeof (EFI_TIME
));
1907 // In the case when the EFI_VARIABLE_APPEND_WRITE attribute is set, only
1908 // when the new TimeStamp value is later than the current timestamp associated
1909 // with the variable, we need associate the new timestamp with the updated value.
1911 if (Variable
->CurrPtr
!= NULL
) {
1912 if (VariableCompareTimeStampInternal (&(((AUTHENTICATED_VARIABLE_HEADER
*) CacheVariable
->CurrPtr
)->TimeStamp
), TimeStamp
)) {
1913 CopyMem (&AuthVariable
->TimeStamp
, TimeStamp
, sizeof (EFI_TIME
));
1915 CopyMem (&AuthVariable
->TimeStamp
, &(((AUTHENTICATED_VARIABLE_HEADER
*) CacheVariable
->CurrPtr
)->TimeStamp
), sizeof (EFI_TIME
));
1923 // The EFI_VARIABLE_APPEND_WRITE attribute will never be set in the returned
1924 // Attributes bitmask parameter of a GetVariable() call.
1926 NextVariable
->Attributes
= Attributes
& (~EFI_VARIABLE_APPEND_WRITE
);
1928 VarNameOffset
= GetVariableHeaderSize ();
1929 VarNameSize
= StrSize (VariableName
);
1931 (UINT8
*) ((UINTN
) NextVariable
+ VarNameOffset
),
1935 VarDataOffset
= VarNameOffset
+ VarNameSize
+ GET_PAD_SIZE (VarNameSize
);
1938 // If DataReady is TRUE, it means the variable data has been saved into
1939 // NextVariable during EFI_VARIABLE_APPEND_WRITE operation preparation.
1943 (UINT8
*) ((UINTN
) NextVariable
+ VarDataOffset
),
1949 CopyMem (GetVendorGuidPtr (NextVariable
), VendorGuid
, sizeof (EFI_GUID
));
1951 // There will be pad bytes after Data, the NextVariable->NameSize and
1952 // NextVariable->DataSize should not include pad size so that variable
1953 // service can get actual size in GetVariable.
1955 SetNameSizeOfVariable (NextVariable
, VarNameSize
);
1956 SetDataSizeOfVariable (NextVariable
, DataSize
);
1959 // The actual size of the variable that stores in storage should
1960 // include pad size.
1962 VarSize
= VarDataOffset
+ DataSize
+ GET_PAD_SIZE (DataSize
);
1963 if ((Attributes
& EFI_VARIABLE_NON_VOLATILE
) != 0) {
1965 // Create a nonvolatile variable.
1969 IsCommonVariable
= FALSE
;
1970 IsCommonUserVariable
= FALSE
;
1971 if ((Attributes
& EFI_VARIABLE_HARDWARE_ERROR_RECORD
) == 0) {
1972 IsCommonVariable
= TRUE
;
1973 IsCommonUserVariable
= IsUserVariable (NextVariable
);
1975 if ((((Attributes
& EFI_VARIABLE_HARDWARE_ERROR_RECORD
) != 0)
1976 && ((VarSize
+ mVariableModuleGlobal
->HwErrVariableTotalSize
) > PcdGet32 (PcdHwErrStorageSize
)))
1977 || (IsCommonVariable
&& ((VarSize
+ mVariableModuleGlobal
->CommonVariableTotalSize
) > mVariableModuleGlobal
->CommonVariableSpace
))
1978 || (IsCommonVariable
&& AtRuntime () && ((VarSize
+ mVariableModuleGlobal
->CommonVariableTotalSize
) > mVariableModuleGlobal
->CommonRuntimeVariableSpace
))
1979 || (IsCommonUserVariable
&& ((VarSize
+ mVariableModuleGlobal
->CommonUserVariableTotalSize
) > mVariableModuleGlobal
->CommonMaxUserVariableSpace
))) {
1981 if (IsCommonUserVariable
&& ((VarSize
+ mVariableModuleGlobal
->CommonUserVariableTotalSize
) > mVariableModuleGlobal
->CommonMaxUserVariableSpace
)) {
1982 RecordVarErrorFlag (VAR_ERROR_FLAG_USER_ERROR
, VariableName
, VendorGuid
, Attributes
, VarSize
);
1984 if (IsCommonVariable
&& ((VarSize
+ mVariableModuleGlobal
->CommonVariableTotalSize
) > mVariableModuleGlobal
->CommonRuntimeVariableSpace
)) {
1985 RecordVarErrorFlag (VAR_ERROR_FLAG_SYSTEM_ERROR
, VariableName
, VendorGuid
, Attributes
, VarSize
);
1987 Status
= EFI_OUT_OF_RESOURCES
;
1991 // Perform garbage collection & reclaim operation, and integrate the new variable at the same time.
1994 mVariableModuleGlobal
->VariableGlobal
.NonVolatileVariableBase
,
1995 &mVariableModuleGlobal
->NonVolatileLastVariableOffset
,
1999 HEADER_ALIGN (VarSize
)
2001 if (!EFI_ERROR (Status
)) {
2003 // The new variable has been integrated successfully during reclaiming.
2005 if (Variable
->CurrPtr
!= NULL
) {
2006 CacheVariable
->CurrPtr
= (VARIABLE_HEADER
*)((UINTN
) CacheVariable
->StartPtr
+ ((UINTN
) Variable
->CurrPtr
- (UINTN
) Variable
->StartPtr
));
2007 CacheVariable
->InDeletedTransitionPtr
= NULL
;
2009 UpdateVariableInfo (VariableName
, VendorGuid
, FALSE
, FALSE
, TRUE
, FALSE
, FALSE
);
2010 FlushHobVariableToFlash (VariableName
, VendorGuid
);
2012 if (IsCommonUserVariable
&& ((VarSize
+ mVariableModuleGlobal
->CommonUserVariableTotalSize
) > mVariableModuleGlobal
->CommonMaxUserVariableSpace
)) {
2013 RecordVarErrorFlag (VAR_ERROR_FLAG_USER_ERROR
, VariableName
, VendorGuid
, Attributes
, VarSize
);
2015 if (IsCommonVariable
&& ((VarSize
+ mVariableModuleGlobal
->CommonVariableTotalSize
) > mVariableModuleGlobal
->CommonVariableSpace
)) {
2016 RecordVarErrorFlag (VAR_ERROR_FLAG_SYSTEM_ERROR
, VariableName
, VendorGuid
, Attributes
, VarSize
);
2022 if (!mVariableModuleGlobal
->VariableGlobal
.EmuNvMode
) {
2025 // 1. Write variable header
2026 // 2. Set variable state to header valid
2027 // 3. Write variable data
2028 // 4. Set variable state to valid
2033 Status
= UpdateVariableStore (
2034 &mVariableModuleGlobal
->VariableGlobal
,
2038 mVariableModuleGlobal
->NonVolatileLastVariableOffset
,
2039 (UINT32
) GetVariableHeaderSize (),
2040 (UINT8
*) NextVariable
2043 if (EFI_ERROR (Status
)) {
2050 NextVariable
->State
= VAR_HEADER_VALID_ONLY
;
2051 Status
= UpdateVariableStore (
2052 &mVariableModuleGlobal
->VariableGlobal
,
2056 mVariableModuleGlobal
->NonVolatileLastVariableOffset
+ OFFSET_OF (VARIABLE_HEADER
, State
),
2058 &NextVariable
->State
2061 if (EFI_ERROR (Status
)) {
2067 Status
= UpdateVariableStore (
2068 &mVariableModuleGlobal
->VariableGlobal
,
2072 mVariableModuleGlobal
->NonVolatileLastVariableOffset
+ GetVariableHeaderSize (),
2073 (UINT32
) (VarSize
- GetVariableHeaderSize ()),
2074 (UINT8
*) NextVariable
+ GetVariableHeaderSize ()
2077 if (EFI_ERROR (Status
)) {
2083 NextVariable
->State
= VAR_ADDED
;
2084 Status
= UpdateVariableStore (
2085 &mVariableModuleGlobal
->VariableGlobal
,
2089 mVariableModuleGlobal
->NonVolatileLastVariableOffset
+ OFFSET_OF (VARIABLE_HEADER
, State
),
2091 &NextVariable
->State
2094 if (EFI_ERROR (Status
)) {
2099 // Update the memory copy of Flash region.
2101 CopyMem ((UINT8
*)mNvVariableCache
+ mVariableModuleGlobal
->NonVolatileLastVariableOffset
, (UINT8
*)NextVariable
, VarSize
);
2104 // Emulated non-volatile variable mode.
2106 NextVariable
->State
= VAR_ADDED
;
2107 Status
= UpdateVariableStore (
2108 &mVariableModuleGlobal
->VariableGlobal
,
2112 mVariableModuleGlobal
->NonVolatileLastVariableOffset
,
2114 (UINT8
*) NextVariable
2117 if (EFI_ERROR (Status
)) {
2122 mVariableModuleGlobal
->NonVolatileLastVariableOffset
+= HEADER_ALIGN (VarSize
);
2124 if ((Attributes
& EFI_VARIABLE_HARDWARE_ERROR_RECORD
) != 0) {
2125 mVariableModuleGlobal
->HwErrVariableTotalSize
+= HEADER_ALIGN (VarSize
);
2127 mVariableModuleGlobal
->CommonVariableTotalSize
+= HEADER_ALIGN (VarSize
);
2128 if (IsCommonUserVariable
) {
2129 mVariableModuleGlobal
->CommonUserVariableTotalSize
+= HEADER_ALIGN (VarSize
);
2134 // Create a volatile variable.
2138 if ((UINT32
) (VarSize
+ mVariableModuleGlobal
->VolatileLastVariableOffset
) >
2139 ((VARIABLE_STORE_HEADER
*) ((UINTN
) (mVariableModuleGlobal
->VariableGlobal
.VolatileVariableBase
)))->Size
) {
2141 // Perform garbage collection & reclaim operation, and integrate the new variable at the same time.
2144 mVariableModuleGlobal
->VariableGlobal
.VolatileVariableBase
,
2145 &mVariableModuleGlobal
->VolatileLastVariableOffset
,
2149 HEADER_ALIGN (VarSize
)
2151 if (!EFI_ERROR (Status
)) {
2153 // The new variable has been integrated successfully during reclaiming.
2155 if (Variable
->CurrPtr
!= NULL
) {
2156 CacheVariable
->CurrPtr
= (VARIABLE_HEADER
*)((UINTN
) CacheVariable
->StartPtr
+ ((UINTN
) Variable
->CurrPtr
- (UINTN
) Variable
->StartPtr
));
2157 CacheVariable
->InDeletedTransitionPtr
= NULL
;
2159 UpdateVariableInfo (VariableName
, VendorGuid
, TRUE
, FALSE
, TRUE
, FALSE
, FALSE
);
2164 NextVariable
->State
= VAR_ADDED
;
2165 Status
= UpdateVariableStore (
2166 &mVariableModuleGlobal
->VariableGlobal
,
2170 mVariableModuleGlobal
->VolatileLastVariableOffset
,
2172 (UINT8
*) NextVariable
2175 if (EFI_ERROR (Status
)) {
2179 mVariableModuleGlobal
->VolatileLastVariableOffset
+= HEADER_ALIGN (VarSize
);
2183 // Mark the old variable as deleted.
2185 if (!EFI_ERROR (Status
) && Variable
->CurrPtr
!= NULL
) {
2186 if (Variable
->InDeletedTransitionPtr
!= NULL
) {
2188 // Both ADDED and IN_DELETED_TRANSITION old variable are present,
2189 // set IN_DELETED_TRANSITION one to DELETED state first.
2191 ASSERT (CacheVariable
->InDeletedTransitionPtr
!= NULL
);
2192 State
= CacheVariable
->InDeletedTransitionPtr
->State
;
2193 State
&= VAR_DELETED
;
2194 Status
= UpdateVariableStore (
2195 &mVariableModuleGlobal
->VariableGlobal
,
2199 (UINTN
) &Variable
->InDeletedTransitionPtr
->State
,
2203 if (!EFI_ERROR (Status
)) {
2204 if (!Variable
->Volatile
) {
2205 CacheVariable
->InDeletedTransitionPtr
->State
= State
;
2212 State
= CacheVariable
->CurrPtr
->State
;
2213 State
&= VAR_DELETED
;
2215 Status
= UpdateVariableStore (
2216 &mVariableModuleGlobal
->VariableGlobal
,
2220 (UINTN
) &Variable
->CurrPtr
->State
,
2224 if (!EFI_ERROR (Status
) && !Variable
->Volatile
) {
2225 CacheVariable
->CurrPtr
->State
= State
;
2229 if (!EFI_ERROR (Status
)) {
2230 UpdateVariableInfo (VariableName
, VendorGuid
, Volatile
, FALSE
, TRUE
, FALSE
, FALSE
);
2232 FlushHobVariableToFlash (VariableName
, VendorGuid
);
2242 This code finds variable in storage blocks (Volatile or Non-Volatile).
2244 Caution: This function may receive untrusted input.
2245 This function may be invoked in SMM mode, and datasize is external input.
2246 This function will do basic validation, before parse the data.
2248 @param VariableName Name of Variable to be found.
2249 @param VendorGuid Variable vendor GUID.
2250 @param Attributes Attribute value of the variable found.
2251 @param DataSize Size of Data found. If size is less than the
2252 data, this value contains the required size.
2253 @param Data The buffer to return the contents of the variable. May be NULL
2254 with a zero DataSize in order to determine the size buffer needed.
2256 @return EFI_INVALID_PARAMETER Invalid parameter.
2257 @return EFI_SUCCESS Find the specified variable.
2258 @return EFI_NOT_FOUND Not found.
2259 @return EFI_BUFFER_TO_SMALL DataSize is too small for the result.
2264 VariableServiceGetVariable (
2265 IN CHAR16
*VariableName
,
2266 IN EFI_GUID
*VendorGuid
,
2267 OUT UINT32
*Attributes OPTIONAL
,
2268 IN OUT UINTN
*DataSize
,
2269 OUT VOID
*Data OPTIONAL
2273 VARIABLE_POINTER_TRACK Variable
;
2276 if (VariableName
== NULL
|| VendorGuid
== NULL
|| DataSize
== NULL
) {
2277 return EFI_INVALID_PARAMETER
;
2280 if (VariableName
[0] == 0) {
2281 return EFI_NOT_FOUND
;
2284 AcquireLockOnlyAtBootTime(&mVariableModuleGlobal
->VariableGlobal
.VariableServicesLock
);
2286 Status
= FindVariable (VariableName
, VendorGuid
, &Variable
, &mVariableModuleGlobal
->VariableGlobal
, FALSE
);
2287 if (Variable
.CurrPtr
== NULL
|| EFI_ERROR (Status
)) {
2294 VarDataSize
= DataSizeOfVariable (Variable
.CurrPtr
);
2295 ASSERT (VarDataSize
!= 0);
2297 if (*DataSize
>= VarDataSize
) {
2299 Status
= EFI_INVALID_PARAMETER
;
2303 CopyMem (Data
, GetVariableDataPtr (Variable
.CurrPtr
), VarDataSize
);
2304 if (Attributes
!= NULL
) {
2305 *Attributes
= Variable
.CurrPtr
->Attributes
;
2308 *DataSize
= VarDataSize
;
2309 UpdateVariableInfo (VariableName
, VendorGuid
, Variable
.Volatile
, TRUE
, FALSE
, FALSE
, FALSE
);
2311 Status
= EFI_SUCCESS
;
2314 *DataSize
= VarDataSize
;
2315 Status
= EFI_BUFFER_TOO_SMALL
;
2320 ReleaseLockOnlyAtBootTime (&mVariableModuleGlobal
->VariableGlobal
.VariableServicesLock
);
2326 This code Finds the Next available variable.
2328 Caution: This function may receive untrusted input.
2329 This function may be invoked in SMM mode. This function will do basic validation, before parse the data.
2331 @param VariableNameSize The size of the VariableName buffer. The size must be large
2332 enough to fit input string supplied in VariableName buffer.
2333 @param VariableName Pointer to variable name.
2334 @param VendorGuid Variable Vendor Guid.
2336 @retval EFI_SUCCESS The function completed successfully.
2337 @retval EFI_NOT_FOUND The next variable was not found.
2338 @retval EFI_BUFFER_TOO_SMALL The VariableNameSize is too small for the result.
2339 VariableNameSize has been updated with the size needed to complete the request.
2340 @retval EFI_INVALID_PARAMETER VariableNameSize is NULL.
2341 @retval EFI_INVALID_PARAMETER VariableName is NULL.
2342 @retval EFI_INVALID_PARAMETER VendorGuid is NULL.
2343 @retval EFI_INVALID_PARAMETER The input values of VariableName and VendorGuid are not a name and
2344 GUID of an existing variable.
2345 @retval EFI_INVALID_PARAMETER Null-terminator is not found in the first VariableNameSize bytes of
2346 the input VariableName buffer.
2351 VariableServiceGetNextVariableName (
2352 IN OUT UINTN
*VariableNameSize
,
2353 IN OUT CHAR16
*VariableName
,
2354 IN OUT EFI_GUID
*VendorGuid
2360 VARIABLE_HEADER
*VariablePtr
;
2361 VARIABLE_STORE_HEADER
*VariableStoreHeader
[VariableStoreTypeMax
];
2363 if (VariableNameSize
== NULL
|| VariableName
== NULL
|| VendorGuid
== NULL
) {
2364 return EFI_INVALID_PARAMETER
;
2368 // Calculate the possible maximum length of name string, including the Null terminator.
2370 MaxLen
= *VariableNameSize
/ sizeof (CHAR16
);
2371 if ((MaxLen
== 0) || (StrnLenS (VariableName
, MaxLen
) == MaxLen
)) {
2373 // Null-terminator is not found in the first VariableNameSize bytes of the input VariableName buffer,
2374 // follow spec to return EFI_INVALID_PARAMETER.
2376 return EFI_INVALID_PARAMETER
;
2379 AcquireLockOnlyAtBootTime(&mVariableModuleGlobal
->VariableGlobal
.VariableServicesLock
);
2382 // 0: Volatile, 1: HOB, 2: Non-Volatile.
2383 // The index and attributes mapping must be kept in this order as FindVariable
2384 // makes use of this mapping to implement search algorithm.
2386 VariableStoreHeader
[VariableStoreTypeVolatile
] = (VARIABLE_STORE_HEADER
*) (UINTN
) mVariableModuleGlobal
->VariableGlobal
.VolatileVariableBase
;
2387 VariableStoreHeader
[VariableStoreTypeHob
] = (VARIABLE_STORE_HEADER
*) (UINTN
) mVariableModuleGlobal
->VariableGlobal
.HobVariableBase
;
2388 VariableStoreHeader
[VariableStoreTypeNv
] = mNvVariableCache
;
2390 Status
= VariableServiceGetNextVariableInternal (VariableName
, VendorGuid
, VariableStoreHeader
, &VariablePtr
);
2391 if (!EFI_ERROR (Status
)) {
2392 VarNameSize
= NameSizeOfVariable (VariablePtr
);
2393 ASSERT (VarNameSize
!= 0);
2394 if (VarNameSize
<= *VariableNameSize
) {
2395 CopyMem (VariableName
, GetVariableNamePtr (VariablePtr
), VarNameSize
);
2396 CopyMem (VendorGuid
, GetVendorGuidPtr (VariablePtr
), sizeof (EFI_GUID
));
2397 Status
= EFI_SUCCESS
;
2399 Status
= EFI_BUFFER_TOO_SMALL
;
2402 *VariableNameSize
= VarNameSize
;
2405 ReleaseLockOnlyAtBootTime (&mVariableModuleGlobal
->VariableGlobal
.VariableServicesLock
);
2411 This code sets variable in storage blocks (Volatile or Non-Volatile).
2413 Caution: This function may receive untrusted input.
2414 This function may be invoked in SMM mode, and datasize and data are external input.
2415 This function will do basic validation, before parse the data.
2416 This function will parse the authentication carefully to avoid security issues, like
2417 buffer overflow, integer overflow.
2418 This function will check attribute carefully to avoid authentication bypass.
2420 @param VariableName Name of Variable to be found.
2421 @param VendorGuid Variable vendor GUID.
2422 @param Attributes Attribute value of the variable found
2423 @param DataSize Size of Data found. If size is less than the
2424 data, this value contains the required size.
2425 @param Data Data pointer.
2427 @return EFI_INVALID_PARAMETER Invalid parameter.
2428 @return EFI_SUCCESS Set successfully.
2429 @return EFI_OUT_OF_RESOURCES Resource not enough to set variable.
2430 @return EFI_NOT_FOUND Not found.
2431 @return EFI_WRITE_PROTECTED Variable is read-only.
2436 VariableServiceSetVariable (
2437 IN CHAR16
*VariableName
,
2438 IN EFI_GUID
*VendorGuid
,
2439 IN UINT32 Attributes
,
2444 VARIABLE_POINTER_TRACK Variable
;
2446 VARIABLE_HEADER
*NextVariable
;
2447 EFI_PHYSICAL_ADDRESS Point
;
2451 // Check input parameters.
2453 if (VariableName
== NULL
|| VariableName
[0] == 0 || VendorGuid
== NULL
) {
2454 return EFI_INVALID_PARAMETER
;
2457 if (DataSize
!= 0 && Data
== NULL
) {
2458 return EFI_INVALID_PARAMETER
;
2462 // Check for reserverd bit in variable attribute.
2463 // EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS is deprecated but we still allow
2464 // the delete operation of common authenticated variable at user physical presence.
2465 // So leave EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS attribute check to AuthVariableLib
2467 if ((Attributes
& (~(EFI_VARIABLE_ATTRIBUTES_MASK
| EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS
))) != 0) {
2468 return EFI_INVALID_PARAMETER
;
2472 // Make sure if runtime bit is set, boot service bit is set also.
2474 if ((Attributes
& (EFI_VARIABLE_RUNTIME_ACCESS
| EFI_VARIABLE_BOOTSERVICE_ACCESS
)) == EFI_VARIABLE_RUNTIME_ACCESS
) {
2475 if ((Attributes
& EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS
) != 0) {
2476 return EFI_UNSUPPORTED
;
2478 return EFI_INVALID_PARAMETER
;
2480 } else if ((Attributes
& VARIABLE_ATTRIBUTE_AT_AW
) != 0) {
2481 if (!mVariableModuleGlobal
->VariableGlobal
.AuthSupport
) {
2483 // Not support authenticated variable write.
2485 return EFI_INVALID_PARAMETER
;
2487 } else if ((Attributes
& EFI_VARIABLE_HARDWARE_ERROR_RECORD
) != 0) {
2488 if (PcdGet32 (PcdHwErrStorageSize
) == 0) {
2490 // Not support harware error record variable variable.
2492 return EFI_INVALID_PARAMETER
;
2497 // EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS and EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS attribute
2498 // cannot be set both.
2500 if (((Attributes
& EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS
) == EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS
)
2501 && ((Attributes
& EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS
) == EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS
)) {
2502 return EFI_UNSUPPORTED
;
2505 if ((Attributes
& EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS
) == EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS
) {
2507 // If DataSize == AUTHINFO_SIZE and then PayloadSize is 0.
2508 // Maybe it's the delete operation of common authenticated variable at user physical presence.
2510 if (DataSize
!= AUTHINFO_SIZE
) {
2511 return EFI_UNSUPPORTED
;
2513 PayloadSize
= DataSize
- AUTHINFO_SIZE
;
2514 } else if ((Attributes
& EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS
) == EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS
) {
2516 // Sanity check for EFI_VARIABLE_AUTHENTICATION_2 descriptor.
2518 if (DataSize
< OFFSET_OF_AUTHINFO2_CERT_DATA
||
2519 ((EFI_VARIABLE_AUTHENTICATION_2
*) Data
)->AuthInfo
.Hdr
.dwLength
> DataSize
- (OFFSET_OF (EFI_VARIABLE_AUTHENTICATION_2
, AuthInfo
)) ||
2520 ((EFI_VARIABLE_AUTHENTICATION_2
*) Data
)->AuthInfo
.Hdr
.dwLength
< OFFSET_OF (WIN_CERTIFICATE_UEFI_GUID
, CertData
)) {
2521 return EFI_SECURITY_VIOLATION
;
2524 // The VariableSpeculationBarrier() call here is to ensure the above sanity
2525 // check for the EFI_VARIABLE_AUTHENTICATION_2 descriptor has been completed
2526 // before the execution of subsequent codes.
2528 VariableSpeculationBarrier ();
2529 PayloadSize
= DataSize
- AUTHINFO2_SIZE (Data
);
2531 PayloadSize
= DataSize
;
2534 if ((UINTN
)(~0) - PayloadSize
< StrSize(VariableName
)){
2536 // Prevent whole variable size overflow
2538 return EFI_INVALID_PARAMETER
;
2542 // The size of the VariableName, including the Unicode Null in bytes plus
2543 // the DataSize is limited to maximum size of PcdGet32 (PcdMaxHardwareErrorVariableSize)
2544 // bytes for HwErrRec#### variable.
2546 if ((Attributes
& EFI_VARIABLE_HARDWARE_ERROR_RECORD
) == EFI_VARIABLE_HARDWARE_ERROR_RECORD
) {
2547 if (StrSize (VariableName
) + PayloadSize
> PcdGet32 (PcdMaxHardwareErrorVariableSize
) - GetVariableHeaderSize ()) {
2548 return EFI_INVALID_PARAMETER
;
2552 // The size of the VariableName, including the Unicode Null in bytes plus
2553 // the DataSize is limited to maximum size of Max(Auth|Volatile)VariableSize bytes.
2555 if ((Attributes
& VARIABLE_ATTRIBUTE_AT_AW
) != 0) {
2556 if (StrSize (VariableName
) + PayloadSize
> mVariableModuleGlobal
->MaxAuthVariableSize
- GetVariableHeaderSize ()) {
2557 DEBUG ((DEBUG_ERROR
,
2558 "%a: Failed to set variable '%s' with Guid %g\n",
2559 __FUNCTION__
, VariableName
, VendorGuid
));
2560 DEBUG ((DEBUG_ERROR
,
2561 "NameSize(0x%x) + PayloadSize(0x%x) > "
2562 "MaxAuthVariableSize(0x%x) - HeaderSize(0x%x)\n",
2563 StrSize (VariableName
), PayloadSize
,
2564 mVariableModuleGlobal
->MaxAuthVariableSize
,
2565 GetVariableHeaderSize ()
2567 return EFI_INVALID_PARAMETER
;
2569 } else if ((Attributes
& EFI_VARIABLE_NON_VOLATILE
) != 0) {
2570 if (StrSize (VariableName
) + PayloadSize
> mVariableModuleGlobal
->MaxVariableSize
- GetVariableHeaderSize ()) {
2571 DEBUG ((DEBUG_ERROR
,
2572 "%a: Failed to set variable '%s' with Guid %g\n",
2573 __FUNCTION__
, VariableName
, VendorGuid
));
2574 DEBUG ((DEBUG_ERROR
,
2575 "NameSize(0x%x) + PayloadSize(0x%x) > "
2576 "MaxVariableSize(0x%x) - HeaderSize(0x%x)\n",
2577 StrSize (VariableName
), PayloadSize
,
2578 mVariableModuleGlobal
->MaxVariableSize
,
2579 GetVariableHeaderSize ()
2581 return EFI_INVALID_PARAMETER
;
2584 if (StrSize (VariableName
) + PayloadSize
> mVariableModuleGlobal
->MaxVolatileVariableSize
- GetVariableHeaderSize ()) {
2585 DEBUG ((DEBUG_ERROR
,
2586 "%a: Failed to set variable '%s' with Guid %g\n",
2587 __FUNCTION__
, VariableName
, VendorGuid
));
2588 DEBUG ((DEBUG_ERROR
,
2589 "NameSize(0x%x) + PayloadSize(0x%x) > "
2590 "MaxVolatileVariableSize(0x%x) - HeaderSize(0x%x)\n",
2591 StrSize (VariableName
), PayloadSize
,
2592 mVariableModuleGlobal
->MaxVolatileVariableSize
,
2593 GetVariableHeaderSize ()
2595 return EFI_INVALID_PARAMETER
;
2601 // Special Handling for MOR Lock variable.
2603 Status
= SetVariableCheckHandlerMor (VariableName
, VendorGuid
, Attributes
, PayloadSize
, (VOID
*) ((UINTN
) Data
+ DataSize
- PayloadSize
));
2604 if (Status
== EFI_ALREADY_STARTED
) {
2606 // EFI_ALREADY_STARTED means the SetVariable() action is handled inside of SetVariableCheckHandlerMor().
2607 // Variable driver can just return SUCCESS.
2611 if (EFI_ERROR (Status
)) {
2615 Status
= VarCheckLibSetVariableCheck (VariableName
, VendorGuid
, Attributes
, PayloadSize
, (VOID
*) ((UINTN
) Data
+ DataSize
- PayloadSize
), mRequestSource
);
2616 if (EFI_ERROR (Status
)) {
2620 AcquireLockOnlyAtBootTime(&mVariableModuleGlobal
->VariableGlobal
.VariableServicesLock
);
2623 // Consider reentrant in MCA/INIT/NMI. It needs be reupdated.
2625 if (1 < InterlockedIncrement (&mVariableModuleGlobal
->VariableGlobal
.ReentrantState
)) {
2626 Point
= mVariableModuleGlobal
->VariableGlobal
.NonVolatileVariableBase
;
2628 // Parse non-volatile variable data and get last variable offset.
2630 NextVariable
= GetStartPointer ((VARIABLE_STORE_HEADER
*) (UINTN
) Point
);
2631 while (IsValidVariableHeader (NextVariable
, GetEndPointer ((VARIABLE_STORE_HEADER
*) (UINTN
) Point
))) {
2632 NextVariable
= GetNextVariablePtr (NextVariable
);
2634 mVariableModuleGlobal
->NonVolatileLastVariableOffset
= (UINTN
) NextVariable
- (UINTN
) Point
;
2638 // Check whether the input variable is already existed.
2640 Status
= FindVariable (VariableName
, VendorGuid
, &Variable
, &mVariableModuleGlobal
->VariableGlobal
, TRUE
);
2641 if (!EFI_ERROR (Status
)) {
2642 if (((Variable
.CurrPtr
->Attributes
& EFI_VARIABLE_RUNTIME_ACCESS
) == 0) && AtRuntime ()) {
2643 Status
= EFI_WRITE_PROTECTED
;
2646 if (Attributes
!= 0 && (Attributes
& (~EFI_VARIABLE_APPEND_WRITE
)) != Variable
.CurrPtr
->Attributes
) {
2648 // If a preexisting variable is rewritten with different attributes, SetVariable() shall not
2649 // modify the variable and shall return EFI_INVALID_PARAMETER. Two exceptions to this rule:
2650 // 1. No access attributes specified
2651 // 2. The only attribute differing is EFI_VARIABLE_APPEND_WRITE
2653 Status
= EFI_INVALID_PARAMETER
;
2654 DEBUG ((EFI_D_INFO
, "[Variable]: Rewritten a preexisting variable(0x%08x) with different attributes(0x%08x) - %g:%s\n", Variable
.CurrPtr
->Attributes
, Attributes
, VendorGuid
, VariableName
));
2659 if (!FeaturePcdGet (PcdUefiVariableDefaultLangDeprecate
)) {
2661 // Hook the operation of setting PlatformLangCodes/PlatformLang and LangCodes/Lang.
2663 Status
= AutoUpdateLangVariable (VariableName
, Data
, DataSize
);
2664 if (EFI_ERROR (Status
)) {
2666 // The auto update operation failed, directly return to avoid inconsistency between PlatformLang and Lang.
2672 if (mVariableModuleGlobal
->VariableGlobal
.AuthSupport
) {
2673 Status
= AuthVariableLibProcessVariable (VariableName
, VendorGuid
, Data
, DataSize
, Attributes
);
2675 Status
= UpdateVariable (VariableName
, VendorGuid
, Data
, DataSize
, Attributes
, 0, 0, &Variable
, NULL
);
2679 InterlockedDecrement (&mVariableModuleGlobal
->VariableGlobal
.ReentrantState
);
2680 ReleaseLockOnlyAtBootTime (&mVariableModuleGlobal
->VariableGlobal
.VariableServicesLock
);
2682 if (!AtRuntime ()) {
2683 if (!EFI_ERROR (Status
)) {
2696 This code returns information about the EFI variables.
2698 Caution: This function may receive untrusted input.
2699 This function may be invoked in SMM mode. This function will do basic validation, before parse the data.
2701 @param Attributes Attributes bitmask to specify the type of variables
2702 on which to return information.
2703 @param MaximumVariableStorageSize Pointer to the maximum size of the storage space available
2704 for the EFI variables associated with the attributes specified.
2705 @param RemainingVariableStorageSize Pointer to the remaining size of the storage space available
2706 for EFI variables associated with the attributes specified.
2707 @param MaximumVariableSize Pointer to the maximum size of an individual EFI variables
2708 associated with the attributes specified.
2710 @return EFI_SUCCESS Query successfully.
2715 VariableServiceQueryVariableInfoInternal (
2716 IN UINT32 Attributes
,
2717 OUT UINT64
*MaximumVariableStorageSize
,
2718 OUT UINT64
*RemainingVariableStorageSize
,
2719 OUT UINT64
*MaximumVariableSize
2722 VARIABLE_HEADER
*Variable
;
2723 VARIABLE_HEADER
*NextVariable
;
2724 UINT64 VariableSize
;
2725 VARIABLE_STORE_HEADER
*VariableStoreHeader
;
2726 UINT64 CommonVariableTotalSize
;
2727 UINT64 HwErrVariableTotalSize
;
2729 VARIABLE_POINTER_TRACK VariablePtrTrack
;
2731 CommonVariableTotalSize
= 0;
2732 HwErrVariableTotalSize
= 0;
2734 if((Attributes
& EFI_VARIABLE_NON_VOLATILE
) == 0) {
2736 // Query is Volatile related.
2738 VariableStoreHeader
= (VARIABLE_STORE_HEADER
*) ((UINTN
) mVariableModuleGlobal
->VariableGlobal
.VolatileVariableBase
);
2741 // Query is Non-Volatile related.
2743 VariableStoreHeader
= mNvVariableCache
;
2747 // Now let's fill *MaximumVariableStorageSize *RemainingVariableStorageSize
2748 // with the storage size (excluding the storage header size).
2750 *MaximumVariableStorageSize
= VariableStoreHeader
->Size
- sizeof (VARIABLE_STORE_HEADER
);
2753 // Harware error record variable needs larger size.
2755 if ((Attributes
& (EFI_VARIABLE_NON_VOLATILE
| EFI_VARIABLE_HARDWARE_ERROR_RECORD
)) == (EFI_VARIABLE_NON_VOLATILE
| EFI_VARIABLE_HARDWARE_ERROR_RECORD
)) {
2756 *MaximumVariableStorageSize
= PcdGet32 (PcdHwErrStorageSize
);
2757 *MaximumVariableSize
= PcdGet32 (PcdMaxHardwareErrorVariableSize
) - GetVariableHeaderSize ();
2759 if ((Attributes
& EFI_VARIABLE_NON_VOLATILE
) != 0) {
2761 *MaximumVariableStorageSize
= mVariableModuleGlobal
->CommonRuntimeVariableSpace
;
2763 *MaximumVariableStorageSize
= mVariableModuleGlobal
->CommonVariableSpace
;
2768 // Let *MaximumVariableSize be Max(Auth|Volatile)VariableSize with the exception of the variable header size.
2770 if ((Attributes
& VARIABLE_ATTRIBUTE_AT_AW
) != 0) {
2771 *MaximumVariableSize
= mVariableModuleGlobal
->MaxAuthVariableSize
- GetVariableHeaderSize ();
2772 } else if ((Attributes
& EFI_VARIABLE_NON_VOLATILE
) != 0) {
2773 *MaximumVariableSize
= mVariableModuleGlobal
->MaxVariableSize
- GetVariableHeaderSize ();
2775 *MaximumVariableSize
= mVariableModuleGlobal
->MaxVolatileVariableSize
- GetVariableHeaderSize ();
2780 // Point to the starting address of the variables.
2782 Variable
= GetStartPointer (VariableStoreHeader
);
2785 // Now walk through the related variable store.
2787 while (IsValidVariableHeader (Variable
, GetEndPointer (VariableStoreHeader
))) {
2788 NextVariable
= GetNextVariablePtr (Variable
);
2789 VariableSize
= (UINT64
) (UINTN
) NextVariable
- (UINT64
) (UINTN
) Variable
;
2793 // We don't take the state of the variables in mind
2794 // when calculating RemainingVariableStorageSize,
2795 // since the space occupied by variables not marked with
2796 // VAR_ADDED is not allowed to be reclaimed in Runtime.
2798 if ((Variable
->Attributes
& EFI_VARIABLE_HARDWARE_ERROR_RECORD
) == EFI_VARIABLE_HARDWARE_ERROR_RECORD
) {
2799 HwErrVariableTotalSize
+= VariableSize
;
2801 CommonVariableTotalSize
+= VariableSize
;
2805 // Only care about Variables with State VAR_ADDED, because
2806 // the space not marked as VAR_ADDED is reclaimable now.
2808 if (Variable
->State
== VAR_ADDED
) {
2809 if ((Variable
->Attributes
& EFI_VARIABLE_HARDWARE_ERROR_RECORD
) == EFI_VARIABLE_HARDWARE_ERROR_RECORD
) {
2810 HwErrVariableTotalSize
+= VariableSize
;
2812 CommonVariableTotalSize
+= VariableSize
;
2814 } else if (Variable
->State
== (VAR_IN_DELETED_TRANSITION
& VAR_ADDED
)) {
2816 // If it is a IN_DELETED_TRANSITION variable,
2817 // and there is not also a same ADDED one at the same time,
2818 // this IN_DELETED_TRANSITION variable is valid.
2820 VariablePtrTrack
.StartPtr
= GetStartPointer (VariableStoreHeader
);
2821 VariablePtrTrack
.EndPtr
= GetEndPointer (VariableStoreHeader
);
2822 Status
= FindVariableEx (
2823 GetVariableNamePtr (Variable
),
2824 GetVendorGuidPtr (Variable
),
2828 if (!EFI_ERROR (Status
) && VariablePtrTrack
.CurrPtr
->State
!= VAR_ADDED
) {
2829 if ((Variable
->Attributes
& EFI_VARIABLE_HARDWARE_ERROR_RECORD
) == EFI_VARIABLE_HARDWARE_ERROR_RECORD
) {
2830 HwErrVariableTotalSize
+= VariableSize
;
2832 CommonVariableTotalSize
+= VariableSize
;
2839 // Go to the next one.
2841 Variable
= NextVariable
;
2844 if ((Attributes
& EFI_VARIABLE_HARDWARE_ERROR_RECORD
) == EFI_VARIABLE_HARDWARE_ERROR_RECORD
){
2845 *RemainingVariableStorageSize
= *MaximumVariableStorageSize
- HwErrVariableTotalSize
;
2847 if (*MaximumVariableStorageSize
< CommonVariableTotalSize
) {
2848 *RemainingVariableStorageSize
= 0;
2850 *RemainingVariableStorageSize
= *MaximumVariableStorageSize
- CommonVariableTotalSize
;
2854 if (*RemainingVariableStorageSize
< GetVariableHeaderSize ()) {
2855 *MaximumVariableSize
= 0;
2856 } else if ((*RemainingVariableStorageSize
- GetVariableHeaderSize ()) < *MaximumVariableSize
) {
2857 *MaximumVariableSize
= *RemainingVariableStorageSize
- GetVariableHeaderSize ();
2865 This code returns information about the EFI variables.
2867 Caution: This function may receive untrusted input.
2868 This function may be invoked in SMM mode. This function will do basic validation, before parse the data.
2870 @param Attributes Attributes bitmask to specify the type of variables
2871 on which to return information.
2872 @param MaximumVariableStorageSize Pointer to the maximum size of the storage space available
2873 for the EFI variables associated with the attributes specified.
2874 @param RemainingVariableStorageSize Pointer to the remaining size of the storage space available
2875 for EFI variables associated with the attributes specified.
2876 @param MaximumVariableSize Pointer to the maximum size of an individual EFI variables
2877 associated with the attributes specified.
2879 @return EFI_INVALID_PARAMETER An invalid combination of attribute bits was supplied.
2880 @return EFI_SUCCESS Query successfully.
2881 @return EFI_UNSUPPORTED The attribute is not supported on this platform.
2886 VariableServiceQueryVariableInfo (
2887 IN UINT32 Attributes
,
2888 OUT UINT64
*MaximumVariableStorageSize
,
2889 OUT UINT64
*RemainingVariableStorageSize
,
2890 OUT UINT64
*MaximumVariableSize
2895 if(MaximumVariableStorageSize
== NULL
|| RemainingVariableStorageSize
== NULL
|| MaximumVariableSize
== NULL
|| Attributes
== 0) {
2896 return EFI_INVALID_PARAMETER
;
2899 if ((Attributes
& EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS
) != 0) {
2901 // Deprecated attribute, make this check as highest priority.
2903 return EFI_UNSUPPORTED
;
2906 if ((Attributes
& EFI_VARIABLE_ATTRIBUTES_MASK
) == 0) {
2908 // Make sure the Attributes combination is supported by the platform.
2910 return EFI_UNSUPPORTED
;
2911 } else if ((Attributes
& (EFI_VARIABLE_RUNTIME_ACCESS
| EFI_VARIABLE_BOOTSERVICE_ACCESS
)) == EFI_VARIABLE_RUNTIME_ACCESS
) {
2913 // Make sure if runtime bit is set, boot service bit is set also.
2915 return EFI_INVALID_PARAMETER
;
2916 } else if (AtRuntime () && ((Attributes
& EFI_VARIABLE_RUNTIME_ACCESS
) == 0)) {
2918 // Make sure RT Attribute is set if we are in Runtime phase.
2920 return EFI_INVALID_PARAMETER
;
2921 } else if ((Attributes
& (EFI_VARIABLE_NON_VOLATILE
| EFI_VARIABLE_HARDWARE_ERROR_RECORD
)) == EFI_VARIABLE_HARDWARE_ERROR_RECORD
) {
2923 // Make sure Hw Attribute is set with NV.
2925 return EFI_INVALID_PARAMETER
;
2926 } else if ((Attributes
& VARIABLE_ATTRIBUTE_AT_AW
) != 0) {
2927 if (!mVariableModuleGlobal
->VariableGlobal
.AuthSupport
) {
2929 // Not support authenticated variable write.
2931 return EFI_UNSUPPORTED
;
2933 } else if ((Attributes
& EFI_VARIABLE_HARDWARE_ERROR_RECORD
) != 0) {
2934 if (PcdGet32 (PcdHwErrStorageSize
) == 0) {
2936 // Not support harware error record variable variable.
2938 return EFI_UNSUPPORTED
;
2942 AcquireLockOnlyAtBootTime(&mVariableModuleGlobal
->VariableGlobal
.VariableServicesLock
);
2944 Status
= VariableServiceQueryVariableInfoInternal (
2946 MaximumVariableStorageSize
,
2947 RemainingVariableStorageSize
,
2951 ReleaseLockOnlyAtBootTime (&mVariableModuleGlobal
->VariableGlobal
.VariableServicesLock
);
2956 This function reclaims variable storage if free size is below the threshold.
2958 Caution: This function may be invoked at SMM mode.
2959 Care must be taken to make sure not security issue.
2968 UINTN RemainingCommonRuntimeVariableSpace
;
2969 UINTN RemainingHwErrVariableSpace
;
2970 STATIC BOOLEAN Reclaimed
;
2973 // This function will be called only once at EndOfDxe or ReadyToBoot event.
2980 Status
= EFI_SUCCESS
;
2982 if (mVariableModuleGlobal
->CommonRuntimeVariableSpace
< mVariableModuleGlobal
->CommonVariableTotalSize
) {
2983 RemainingCommonRuntimeVariableSpace
= 0;
2985 RemainingCommonRuntimeVariableSpace
= mVariableModuleGlobal
->CommonRuntimeVariableSpace
- mVariableModuleGlobal
->CommonVariableTotalSize
;
2988 RemainingHwErrVariableSpace
= PcdGet32 (PcdHwErrStorageSize
) - mVariableModuleGlobal
->HwErrVariableTotalSize
;
2991 // Check if the free area is below a threshold.
2993 if (((RemainingCommonRuntimeVariableSpace
< mVariableModuleGlobal
->MaxVariableSize
) ||
2994 (RemainingCommonRuntimeVariableSpace
< mVariableModuleGlobal
->MaxAuthVariableSize
)) ||
2995 ((PcdGet32 (PcdHwErrStorageSize
) != 0) &&
2996 (RemainingHwErrVariableSpace
< PcdGet32 (PcdMaxHardwareErrorVariableSize
)))){
2998 mVariableModuleGlobal
->VariableGlobal
.NonVolatileVariableBase
,
2999 &mVariableModuleGlobal
->NonVolatileLastVariableOffset
,
3005 ASSERT_EFI_ERROR (Status
);
3010 Get non-volatile maximum variable size.
3012 @return Non-volatile maximum variable size.
3016 GetNonVolatileMaxVariableSize (
3020 if (PcdGet32 (PcdHwErrStorageSize
) != 0) {
3021 return MAX (MAX (PcdGet32 (PcdMaxVariableSize
), PcdGet32 (PcdMaxAuthVariableSize
)),
3022 PcdGet32 (PcdMaxHardwareErrorVariableSize
));
3024 return MAX (PcdGet32 (PcdMaxVariableSize
), PcdGet32 (PcdMaxAuthVariableSize
));
3029 Get maximum variable size, covering both non-volatile and volatile variables.
3031 @return Maximum variable size.
3035 GetMaxVariableSize (
3039 UINTN MaxVariableSize
;
3041 MaxVariableSize
= GetNonVolatileMaxVariableSize();
3043 // The condition below fails implicitly if PcdMaxVolatileVariableSize equals
3044 // the default zero value.
3046 if (MaxVariableSize
< PcdGet32 (PcdMaxVolatileVariableSize
)) {
3047 MaxVariableSize
= PcdGet32 (PcdMaxVolatileVariableSize
);
3049 return MaxVariableSize
;
3053 Init real non-volatile variable store.
3055 @param[out] VariableStoreBase Output pointer to real non-volatile variable store base.
3057 @retval EFI_SUCCESS Function successfully executed.
3058 @retval EFI_OUT_OF_RESOURCES Fail to allocate enough memory resource.
3059 @retval EFI_VOLUME_CORRUPTED Variable Store or Firmware Volume for Variable Store is corrupted.
3063 InitRealNonVolatileVariableStore (
3064 OUT EFI_PHYSICAL_ADDRESS
*VariableStoreBase
3067 EFI_FIRMWARE_VOLUME_HEADER
*FvHeader
;
3068 VARIABLE_STORE_HEADER
*VariableStore
;
3069 UINT32 VariableStoreLength
;
3070 EFI_HOB_GUID_TYPE
*GuidHob
;
3071 EFI_PHYSICAL_ADDRESS NvStorageBase
;
3072 UINT8
*NvStorageData
;
3073 UINT32 NvStorageSize
;
3074 FAULT_TOLERANT_WRITE_LAST_WRITE_DATA
*FtwLastWriteData
;
3075 UINT32 BackUpOffset
;
3077 UINT32 HwErrStorageSize
;
3078 UINT32 MaxUserNvVariableSpaceSize
;
3079 UINT32 BoottimeReservedNvVariableSpaceSize
;
3083 mVariableModuleGlobal
->FvbInstance
= NULL
;
3086 // Allocate runtime memory used for a memory copy of the FLASH region.
3087 // Keep the memory and the FLASH in sync as updates occur.
3089 NvStorageSize
= PcdGet32 (PcdFlashNvStorageVariableSize
);
3090 NvStorageData
= AllocateRuntimeZeroPool (NvStorageSize
);
3091 if (NvStorageData
== NULL
) {
3092 return EFI_OUT_OF_RESOURCES
;
3095 NvStorageBase
= NV_STORAGE_VARIABLE_BASE
;
3096 ASSERT (NvStorageBase
!= 0);
3099 // Copy NV storage data to the memory buffer.
3101 CopyMem (NvStorageData
, (UINT8
*) (UINTN
) NvStorageBase
, NvStorageSize
);
3103 Status
= GetFtwProtocol ((VOID
**)&FtwProtocol
);
3105 // If FTW protocol has been installed, no need to check FTW last write data hob.
3107 if (EFI_ERROR (Status
)) {
3109 // Check the FTW last write data hob.
3111 GuidHob
= GetFirstGuidHob (&gEdkiiFaultTolerantWriteGuid
);
3112 if (GuidHob
!= NULL
) {
3113 FtwLastWriteData
= (FAULT_TOLERANT_WRITE_LAST_WRITE_DATA
*) GET_GUID_HOB_DATA (GuidHob
);
3114 if (FtwLastWriteData
->TargetAddress
== NvStorageBase
) {
3115 DEBUG ((EFI_D_INFO
, "Variable: NV storage is backed up in spare block: 0x%x\n", (UINTN
) FtwLastWriteData
->SpareAddress
));
3117 // Copy the backed up NV storage data to the memory buffer from spare block.
3119 CopyMem (NvStorageData
, (UINT8
*) (UINTN
) (FtwLastWriteData
->SpareAddress
), NvStorageSize
);
3120 } else if ((FtwLastWriteData
->TargetAddress
> NvStorageBase
) &&
3121 (FtwLastWriteData
->TargetAddress
< (NvStorageBase
+ NvStorageSize
))) {
3123 // Flash NV storage from the Offset is backed up in spare block.
3125 BackUpOffset
= (UINT32
) (FtwLastWriteData
->TargetAddress
- NvStorageBase
);
3126 BackUpSize
= NvStorageSize
- BackUpOffset
;
3127 DEBUG ((EFI_D_INFO
, "Variable: High partial NV storage from offset: %x is backed up in spare block: 0x%x\n", BackUpOffset
, (UINTN
) FtwLastWriteData
->SpareAddress
));
3129 // Copy the partial backed up NV storage data to the memory buffer from spare block.
3131 CopyMem (NvStorageData
+ BackUpOffset
, (UINT8
*) (UINTN
) FtwLastWriteData
->SpareAddress
, BackUpSize
);
3136 FvHeader
= (EFI_FIRMWARE_VOLUME_HEADER
*) NvStorageData
;
3139 // Check if the Firmware Volume is not corrupted
3141 if ((FvHeader
->Signature
!= EFI_FVH_SIGNATURE
) || (!CompareGuid (&gEfiSystemNvDataFvGuid
, &FvHeader
->FileSystemGuid
))) {
3142 FreePool (NvStorageData
);
3143 DEBUG ((EFI_D_ERROR
, "Firmware Volume for Variable Store is corrupted\n"));
3144 return EFI_VOLUME_CORRUPTED
;
3147 VariableStore
= (VARIABLE_STORE_HEADER
*) ((UINTN
) FvHeader
+ FvHeader
->HeaderLength
);
3148 VariableStoreLength
= NvStorageSize
- FvHeader
->HeaderLength
;
3149 ASSERT (sizeof (VARIABLE_STORE_HEADER
) <= VariableStoreLength
);
3150 ASSERT (VariableStore
->Size
== VariableStoreLength
);
3153 // Check if the Variable Store header is not corrupted
3155 if (GetVariableStoreStatus (VariableStore
) != EfiValid
) {
3156 FreePool (NvStorageData
);
3157 DEBUG((EFI_D_ERROR
, "Variable Store header is corrupted\n"));
3158 return EFI_VOLUME_CORRUPTED
;
3161 mNvFvHeaderCache
= FvHeader
;
3163 *VariableStoreBase
= (EFI_PHYSICAL_ADDRESS
) (UINTN
) VariableStore
;
3165 HwErrStorageSize
= PcdGet32 (PcdHwErrStorageSize
);
3166 MaxUserNvVariableSpaceSize
= PcdGet32 (PcdMaxUserNvVariableSpaceSize
);
3167 BoottimeReservedNvVariableSpaceSize
= PcdGet32 (PcdBoottimeReservedNvVariableSpaceSize
);
3170 // Note that in EdkII variable driver implementation, Hardware Error Record type variable
3171 // is stored with common variable in the same NV region. So the platform integrator should
3172 // ensure that the value of PcdHwErrStorageSize is less than the value of
3173 // (VariableStoreLength - sizeof (VARIABLE_STORE_HEADER)).
3175 ASSERT (HwErrStorageSize
< (VariableStoreLength
- sizeof (VARIABLE_STORE_HEADER
)));
3177 // Ensure that the value of PcdMaxUserNvVariableSpaceSize is less than the value of
3178 // (VariableStoreLength - sizeof (VARIABLE_STORE_HEADER)) - PcdGet32 (PcdHwErrStorageSize).
3180 ASSERT (MaxUserNvVariableSpaceSize
< (VariableStoreLength
- sizeof (VARIABLE_STORE_HEADER
) - HwErrStorageSize
));
3182 // Ensure that the value of PcdBoottimeReservedNvVariableSpaceSize is less than the value of
3183 // (VariableStoreLength - sizeof (VARIABLE_STORE_HEADER)) - PcdGet32 (PcdHwErrStorageSize).
3185 ASSERT (BoottimeReservedNvVariableSpaceSize
< (VariableStoreLength
- sizeof (VARIABLE_STORE_HEADER
) - HwErrStorageSize
));
3187 mVariableModuleGlobal
->CommonVariableSpace
= ((UINTN
) VariableStoreLength
- sizeof (VARIABLE_STORE_HEADER
) - HwErrStorageSize
);
3188 mVariableModuleGlobal
->CommonMaxUserVariableSpace
= ((MaxUserNvVariableSpaceSize
!= 0) ? MaxUserNvVariableSpaceSize
: mVariableModuleGlobal
->CommonVariableSpace
);
3189 mVariableModuleGlobal
->CommonRuntimeVariableSpace
= mVariableModuleGlobal
->CommonVariableSpace
- BoottimeReservedNvVariableSpaceSize
;
3191 DEBUG ((EFI_D_INFO
, "Variable driver common space: 0x%x 0x%x 0x%x\n", mVariableModuleGlobal
->CommonVariableSpace
, mVariableModuleGlobal
->CommonMaxUserVariableSpace
, mVariableModuleGlobal
->CommonRuntimeVariableSpace
));
3194 // The max NV variable size should be < (VariableStoreLength - sizeof (VARIABLE_STORE_HEADER)).
3196 ASSERT (GetNonVolatileMaxVariableSize () < (VariableStoreLength
- sizeof (VARIABLE_STORE_HEADER
)));
3202 Init emulated non-volatile variable store.
3204 @param[out] VariableStoreBase Output pointer to emulated non-volatile variable store base.
3206 @retval EFI_SUCCESS Function successfully executed.
3207 @retval EFI_OUT_OF_RESOURCES Fail to allocate enough memory resource.
3211 InitEmuNonVolatileVariableStore (
3212 EFI_PHYSICAL_ADDRESS
*VariableStoreBase
3215 VARIABLE_STORE_HEADER
*VariableStore
;
3216 UINT32 VariableStoreLength
;
3217 BOOLEAN FullyInitializeStore
;
3218 UINT32 HwErrStorageSize
;
3220 FullyInitializeStore
= TRUE
;
3222 VariableStoreLength
= PcdGet32 (PcdVariableStoreSize
);
3223 ASSERT (sizeof (VARIABLE_STORE_HEADER
) <= VariableStoreLength
);
3226 // Allocate memory for variable store.
3228 if (PcdGet64 (PcdEmuVariableNvStoreReserved
) == 0) {
3229 VariableStore
= (VARIABLE_STORE_HEADER
*) AllocateRuntimePool (VariableStoreLength
);
3230 if (VariableStore
== NULL
) {
3231 return EFI_OUT_OF_RESOURCES
;
3235 // A memory location has been reserved for the NV variable store. Certain
3236 // platforms may be able to preserve a memory range across system resets,
3237 // thereby providing better NV variable emulation.
3240 (VARIABLE_STORE_HEADER
*)(VOID
*)(UINTN
)
3241 PcdGet64 (PcdEmuVariableNvStoreReserved
);
3242 if ((VariableStore
->Size
== VariableStoreLength
) &&
3243 (CompareGuid (&VariableStore
->Signature
, &gEfiAuthenticatedVariableGuid
) ||
3244 CompareGuid (&VariableStore
->Signature
, &gEfiVariableGuid
)) &&
3245 (VariableStore
->Format
== VARIABLE_STORE_FORMATTED
) &&
3246 (VariableStore
->State
== VARIABLE_STORE_HEALTHY
)) {
3249 "Variable Store reserved at %p appears to be valid\n",
3252 FullyInitializeStore
= FALSE
;
3256 if (FullyInitializeStore
) {
3257 SetMem (VariableStore
, VariableStoreLength
, 0xff);
3259 // Use gEfiAuthenticatedVariableGuid for potential auth variable support.
3261 CopyGuid (&VariableStore
->Signature
, &gEfiAuthenticatedVariableGuid
);
3262 VariableStore
->Size
= VariableStoreLength
;
3263 VariableStore
->Format
= VARIABLE_STORE_FORMATTED
;
3264 VariableStore
->State
= VARIABLE_STORE_HEALTHY
;
3265 VariableStore
->Reserved
= 0;
3266 VariableStore
->Reserved1
= 0;
3269 *VariableStoreBase
= (EFI_PHYSICAL_ADDRESS
) (UINTN
) VariableStore
;
3271 HwErrStorageSize
= PcdGet32 (PcdHwErrStorageSize
);
3274 // Note that in EdkII variable driver implementation, Hardware Error Record type variable
3275 // is stored with common variable in the same NV region. So the platform integrator should
3276 // ensure that the value of PcdHwErrStorageSize is less than the value of
3277 // (VariableStoreLength - sizeof (VARIABLE_STORE_HEADER)).
3279 ASSERT (HwErrStorageSize
< (VariableStoreLength
- sizeof (VARIABLE_STORE_HEADER
)));
3281 mVariableModuleGlobal
->CommonVariableSpace
= ((UINTN
) VariableStoreLength
- sizeof (VARIABLE_STORE_HEADER
) - HwErrStorageSize
);
3282 mVariableModuleGlobal
->CommonMaxUserVariableSpace
= mVariableModuleGlobal
->CommonVariableSpace
;
3283 mVariableModuleGlobal
->CommonRuntimeVariableSpace
= mVariableModuleGlobal
->CommonVariableSpace
;
3289 Init non-volatile variable store.
3291 @retval EFI_SUCCESS Function successfully executed.
3292 @retval EFI_OUT_OF_RESOURCES Fail to allocate enough memory resource.
3293 @retval EFI_VOLUME_CORRUPTED Variable Store or Firmware Volume for Variable Store is corrupted.
3297 InitNonVolatileVariableStore (
3301 VARIABLE_HEADER
*Variable
;
3302 VARIABLE_HEADER
*NextVariable
;
3303 EFI_PHYSICAL_ADDRESS VariableStoreBase
;
3307 if (PcdGetBool (PcdEmuVariableNvModeEnable
)) {
3308 Status
= InitEmuNonVolatileVariableStore (&VariableStoreBase
);
3309 if (EFI_ERROR (Status
)) {
3312 mVariableModuleGlobal
->VariableGlobal
.EmuNvMode
= TRUE
;
3313 DEBUG ((DEBUG_INFO
, "Variable driver will work at emulated non-volatile variable mode!\n"));
3315 Status
= InitRealNonVolatileVariableStore (&VariableStoreBase
);
3316 if (EFI_ERROR (Status
)) {
3319 mVariableModuleGlobal
->VariableGlobal
.EmuNvMode
= FALSE
;
3322 mVariableModuleGlobal
->VariableGlobal
.NonVolatileVariableBase
= VariableStoreBase
;
3323 mNvVariableCache
= (VARIABLE_STORE_HEADER
*) (UINTN
) VariableStoreBase
;
3324 mVariableModuleGlobal
->VariableGlobal
.AuthFormat
= (BOOLEAN
)(CompareGuid (&mNvVariableCache
->Signature
, &gEfiAuthenticatedVariableGuid
));
3326 mVariableModuleGlobal
->MaxVariableSize
= PcdGet32 (PcdMaxVariableSize
);
3327 mVariableModuleGlobal
->MaxAuthVariableSize
= ((PcdGet32 (PcdMaxAuthVariableSize
) != 0) ? PcdGet32 (PcdMaxAuthVariableSize
) : mVariableModuleGlobal
->MaxVariableSize
);
3330 // Parse non-volatile variable data and get last variable offset.
3332 Variable
= GetStartPointer (mNvVariableCache
);
3333 while (IsValidVariableHeader (Variable
, GetEndPointer (mNvVariableCache
))) {
3334 NextVariable
= GetNextVariablePtr (Variable
);
3335 VariableSize
= (UINTN
) NextVariable
- (UINTN
) Variable
;
3336 if ((Variable
->Attributes
& (EFI_VARIABLE_NON_VOLATILE
| EFI_VARIABLE_HARDWARE_ERROR_RECORD
)) == (EFI_VARIABLE_NON_VOLATILE
| EFI_VARIABLE_HARDWARE_ERROR_RECORD
)) {
3337 mVariableModuleGlobal
->HwErrVariableTotalSize
+= VariableSize
;
3339 mVariableModuleGlobal
->CommonVariableTotalSize
+= VariableSize
;
3342 Variable
= NextVariable
;
3344 mVariableModuleGlobal
->NonVolatileLastVariableOffset
= (UINTN
) Variable
- (UINTN
) mNvVariableCache
;
3350 Flush the HOB variable to flash.
3352 @param[in] VariableName Name of variable has been updated or deleted.
3353 @param[in] VendorGuid Guid of variable has been updated or deleted.
3357 FlushHobVariableToFlash (
3358 IN CHAR16
*VariableName
,
3359 IN EFI_GUID
*VendorGuid
3363 VARIABLE_STORE_HEADER
*VariableStoreHeader
;
3364 VARIABLE_HEADER
*Variable
;
3366 VARIABLE_POINTER_TRACK VariablePtrTrack
;
3372 // Flush the HOB variable to flash.
3374 if (mVariableModuleGlobal
->VariableGlobal
.HobVariableBase
!= 0) {
3375 VariableStoreHeader
= (VARIABLE_STORE_HEADER
*) (UINTN
) mVariableModuleGlobal
->VariableGlobal
.HobVariableBase
;
3377 // Set HobVariableBase to 0, it can avoid SetVariable to call back.
3379 mVariableModuleGlobal
->VariableGlobal
.HobVariableBase
= 0;
3380 for ( Variable
= GetStartPointer (VariableStoreHeader
)
3381 ; IsValidVariableHeader (Variable
, GetEndPointer (VariableStoreHeader
))
3382 ; Variable
= GetNextVariablePtr (Variable
)
3384 if (Variable
->State
!= VAR_ADDED
) {
3386 // The HOB variable has been set to DELETED state in local.
3390 ASSERT ((Variable
->Attributes
& EFI_VARIABLE_NON_VOLATILE
) != 0);
3391 if (VendorGuid
== NULL
|| VariableName
== NULL
||
3392 !CompareGuid (VendorGuid
, GetVendorGuidPtr (Variable
)) ||
3393 StrCmp (VariableName
, GetVariableNamePtr (Variable
)) != 0) {
3394 VariableData
= GetVariableDataPtr (Variable
);
3395 FindVariable (GetVariableNamePtr (Variable
), GetVendorGuidPtr (Variable
), &VariablePtrTrack
, &mVariableModuleGlobal
->VariableGlobal
, FALSE
);
3396 Status
= UpdateVariable (
3397 GetVariableNamePtr (Variable
),
3398 GetVendorGuidPtr (Variable
),
3400 DataSizeOfVariable (Variable
),
3401 Variable
->Attributes
,
3407 DEBUG ((EFI_D_INFO
, "Variable driver flush the HOB variable to flash: %g %s %r\n", GetVendorGuidPtr (Variable
), GetVariableNamePtr (Variable
), Status
));
3410 // The updated or deleted variable is matched with this HOB variable.
3411 // Don't break here because we will try to set other HOB variables
3412 // since this variable could be set successfully.
3414 Status
= EFI_SUCCESS
;
3416 if (!EFI_ERROR (Status
)) {
3418 // If set variable successful, or the updated or deleted variable is matched with the HOB variable,
3419 // set the HOB variable to DELETED state in local.
3421 DEBUG ((EFI_D_INFO
, "Variable driver set the HOB variable to DELETED state in local: %g %s\n", GetVendorGuidPtr (Variable
), GetVariableNamePtr (Variable
)));
3422 Variable
->State
&= VAR_DELETED
;
3429 // We still have HOB variable(s) not flushed in flash.
3431 mVariableModuleGlobal
->VariableGlobal
.HobVariableBase
= (EFI_PHYSICAL_ADDRESS
) (UINTN
) VariableStoreHeader
;
3434 // All HOB variables have been flushed in flash.
3436 DEBUG ((EFI_D_INFO
, "Variable driver: all HOB variables have been flushed in flash.\n"));
3437 if (!AtRuntime ()) {
3438 FreePool ((VOID
*) VariableStoreHeader
);
3446 Initializes variable write service.
3448 @retval EFI_SUCCESS Function successfully executed.
3449 @retval Others Fail to initialize the variable service.
3453 VariableWriteServiceInitialize (
3460 VARIABLE_ENTRY_PROPERTY
*VariableEntry
;
3462 AcquireLockOnlyAtBootTime(&mVariableModuleGlobal
->VariableGlobal
.VariableServicesLock
);
3465 // Check if the free area is really free.
3467 for (Index
= mVariableModuleGlobal
->NonVolatileLastVariableOffset
; Index
< mNvVariableCache
->Size
; Index
++) {
3468 Data
= ((UINT8
*) mNvVariableCache
)[Index
];
3471 // There must be something wrong in variable store, do reclaim operation.
3474 mVariableModuleGlobal
->VariableGlobal
.NonVolatileVariableBase
,
3475 &mVariableModuleGlobal
->NonVolatileLastVariableOffset
,
3481 if (EFI_ERROR (Status
)) {
3482 ReleaseLockOnlyAtBootTime (&mVariableModuleGlobal
->VariableGlobal
.VariableServicesLock
);
3489 FlushHobVariableToFlash (NULL
, NULL
);
3491 Status
= EFI_SUCCESS
;
3492 ZeroMem (&mAuthContextOut
, sizeof (mAuthContextOut
));
3493 if (mVariableModuleGlobal
->VariableGlobal
.AuthFormat
) {
3495 // Authenticated variable initialize.
3497 mAuthContextIn
.StructSize
= sizeof (AUTH_VAR_LIB_CONTEXT_IN
);
3498 mAuthContextIn
.MaxAuthVariableSize
= mVariableModuleGlobal
->MaxAuthVariableSize
- GetVariableHeaderSize ();
3499 Status
= AuthVariableLibInitialize (&mAuthContextIn
, &mAuthContextOut
);
3500 if (!EFI_ERROR (Status
)) {
3501 DEBUG ((EFI_D_INFO
, "Variable driver will work with auth variable support!\n"));
3502 mVariableModuleGlobal
->VariableGlobal
.AuthSupport
= TRUE
;
3503 if (mAuthContextOut
.AuthVarEntry
!= NULL
) {
3504 for (Index
= 0; Index
< mAuthContextOut
.AuthVarEntryCount
; Index
++) {
3505 VariableEntry
= &mAuthContextOut
.AuthVarEntry
[Index
];
3506 Status
= VarCheckLibVariablePropertySet (
3507 VariableEntry
->Name
,
3508 VariableEntry
->Guid
,
3509 &VariableEntry
->VariableProperty
3511 ASSERT_EFI_ERROR (Status
);
3514 } else if (Status
== EFI_UNSUPPORTED
) {
3515 DEBUG ((EFI_D_INFO
, "NOTICE - AuthVariableLibInitialize() returns %r!\n", Status
));
3516 DEBUG ((EFI_D_INFO
, "Variable driver will continue to work without auth variable support!\n"));
3517 mVariableModuleGlobal
->VariableGlobal
.AuthSupport
= FALSE
;
3518 Status
= EFI_SUCCESS
;
3522 if (!EFI_ERROR (Status
)) {
3523 for (Index
= 0; Index
< ARRAY_SIZE (mVariableEntryProperty
); Index
++) {
3524 VariableEntry
= &mVariableEntryProperty
[Index
];
3525 Status
= VarCheckLibVariablePropertySet (VariableEntry
->Name
, VariableEntry
->Guid
, &VariableEntry
->VariableProperty
);
3526 ASSERT_EFI_ERROR (Status
);
3530 ReleaseLockOnlyAtBootTime (&mVariableModuleGlobal
->VariableGlobal
.VariableServicesLock
);
3533 // Initialize MOR Lock variable.
3541 Convert normal variable storage to the allocated auth variable storage.
3543 @param[in] NormalVarStorage Pointer to the normal variable storage header
3545 @retval the allocated auth variable storage
3548 ConvertNormalVarStorageToAuthVarStorage (
3549 VARIABLE_STORE_HEADER
*NormalVarStorage
3552 VARIABLE_HEADER
*StartPtr
;
3554 VARIABLE_HEADER
*EndPtr
;
3555 UINTN AuthVarStroageSize
;
3556 AUTHENTICATED_VARIABLE_HEADER
*AuthStartPtr
;
3557 VARIABLE_STORE_HEADER
*AuthVarStorage
;
3559 AuthVarStroageSize
= sizeof (VARIABLE_STORE_HEADER
);
3561 // Set AuthFormat as FALSE for normal variable storage
3563 mVariableModuleGlobal
->VariableGlobal
.AuthFormat
= FALSE
;
3566 // Calculate Auth Variable Storage Size
3568 StartPtr
= GetStartPointer (NormalVarStorage
);
3569 EndPtr
= GetEndPointer (NormalVarStorage
);
3570 while (StartPtr
< EndPtr
) {
3571 if (StartPtr
->State
== VAR_ADDED
) {
3572 AuthVarStroageSize
= HEADER_ALIGN (AuthVarStroageSize
);
3573 AuthVarStroageSize
+= sizeof (AUTHENTICATED_VARIABLE_HEADER
);
3574 AuthVarStroageSize
+= StartPtr
->NameSize
+ GET_PAD_SIZE (StartPtr
->NameSize
);
3575 AuthVarStroageSize
+= StartPtr
->DataSize
+ GET_PAD_SIZE (StartPtr
->DataSize
);
3577 StartPtr
= GetNextVariablePtr (StartPtr
);
3581 // Allocate Runtime memory for Auth Variable Storage
3583 AuthVarStorage
= AllocateRuntimeZeroPool (AuthVarStroageSize
);
3584 ASSERT (AuthVarStorage
!= NULL
);
3585 if (AuthVarStorage
== NULL
) {
3590 // Copy Variable from Normal storage to Auth storage
3592 StartPtr
= GetStartPointer (NormalVarStorage
);
3593 EndPtr
= GetEndPointer (NormalVarStorage
);
3594 AuthStartPtr
= (AUTHENTICATED_VARIABLE_HEADER
*) GetStartPointer (AuthVarStorage
);
3595 while (StartPtr
< EndPtr
) {
3596 if (StartPtr
->State
== VAR_ADDED
) {
3597 AuthStartPtr
= (AUTHENTICATED_VARIABLE_HEADER
*) HEADER_ALIGN (AuthStartPtr
);
3599 // Copy Variable Header
3601 AuthStartPtr
->StartId
= StartPtr
->StartId
;
3602 AuthStartPtr
->State
= StartPtr
->State
;
3603 AuthStartPtr
->Attributes
= StartPtr
->Attributes
;
3604 AuthStartPtr
->NameSize
= StartPtr
->NameSize
;
3605 AuthStartPtr
->DataSize
= StartPtr
->DataSize
;
3606 CopyGuid (&AuthStartPtr
->VendorGuid
, &StartPtr
->VendorGuid
);
3608 // Copy Variable Name
3610 NextPtr
= (UINT8
*) (AuthStartPtr
+ 1);
3611 CopyMem (NextPtr
, GetVariableNamePtr (StartPtr
), AuthStartPtr
->NameSize
);
3613 // Copy Variable Data
3615 NextPtr
= NextPtr
+ AuthStartPtr
->NameSize
+ GET_PAD_SIZE (AuthStartPtr
->NameSize
);
3616 CopyMem (NextPtr
, GetVariableDataPtr (StartPtr
), AuthStartPtr
->DataSize
);
3618 // Go to next variable
3620 AuthStartPtr
= (AUTHENTICATED_VARIABLE_HEADER
*) (NextPtr
+ AuthStartPtr
->DataSize
+ GET_PAD_SIZE (AuthStartPtr
->DataSize
));
3622 StartPtr
= GetNextVariablePtr (StartPtr
);
3625 // Update Auth Storage Header
3627 AuthVarStorage
->Format
= NormalVarStorage
->Format
;
3628 AuthVarStorage
->State
= NormalVarStorage
->State
;
3629 AuthVarStorage
->Size
= (UINT32
)((UINTN
)AuthStartPtr
- (UINTN
)AuthVarStorage
);
3630 CopyGuid (&AuthVarStorage
->Signature
, &gEfiAuthenticatedVariableGuid
);
3631 ASSERT (AuthVarStorage
->Size
<= AuthVarStroageSize
);
3634 // Restore AuthFormat
3636 mVariableModuleGlobal
->VariableGlobal
.AuthFormat
= TRUE
;
3637 return AuthVarStorage
;
3641 Get HOB variable store.
3643 @param[in] VariableGuid NV variable store signature.
3645 @retval EFI_SUCCESS Function successfully executed.
3646 @retval EFI_OUT_OF_RESOURCES Fail to allocate enough memory resource.
3650 GetHobVariableStore (
3651 IN EFI_GUID
*VariableGuid
3654 VARIABLE_STORE_HEADER
*VariableStoreHeader
;
3655 UINT64 VariableStoreLength
;
3656 EFI_HOB_GUID_TYPE
*GuidHob
;
3657 BOOLEAN NeedConvertNormalToAuth
;
3660 // Make sure there is no more than one Variable HOB.
3663 GuidHob
= GetFirstGuidHob (&gEfiAuthenticatedVariableGuid
);
3664 if (GuidHob
!= NULL
) {
3665 if ((GetNextGuidHob (&gEfiAuthenticatedVariableGuid
, GET_NEXT_HOB (GuidHob
)) != NULL
)) {
3666 DEBUG ((DEBUG_ERROR
, "ERROR: Found two Auth Variable HOBs\n"));
3668 } else if (GetFirstGuidHob (&gEfiVariableGuid
) != NULL
) {
3669 DEBUG ((DEBUG_ERROR
, "ERROR: Found one Auth + one Normal Variable HOBs\n"));
3673 GuidHob
= GetFirstGuidHob (&gEfiVariableGuid
);
3674 if (GuidHob
!= NULL
) {
3675 if ((GetNextGuidHob (&gEfiVariableGuid
, GET_NEXT_HOB (GuidHob
)) != NULL
)) {
3676 DEBUG ((DEBUG_ERROR
, "ERROR: Found two Normal Variable HOBs\n"));
3684 // Combinations supported:
3685 // 1. Normal NV variable store +
3686 // Normal HOB variable store
3687 // 2. Auth NV variable store +
3688 // Auth HOB variable store
3689 // 3. Auth NV variable store +
3690 // Normal HOB variable store (code will convert it to Auth Format)
3692 NeedConvertNormalToAuth
= FALSE
;
3693 GuidHob
= GetFirstGuidHob (VariableGuid
);
3694 if (GuidHob
== NULL
&& VariableGuid
== &gEfiAuthenticatedVariableGuid
) {
3696 // Try getting it from normal variable HOB
3698 GuidHob
= GetFirstGuidHob (&gEfiVariableGuid
);
3699 NeedConvertNormalToAuth
= TRUE
;
3701 if (GuidHob
!= NULL
) {
3702 VariableStoreHeader
= GET_GUID_HOB_DATA (GuidHob
);
3703 VariableStoreLength
= GuidHob
->Header
.HobLength
- sizeof (EFI_HOB_GUID_TYPE
);
3704 if (GetVariableStoreStatus (VariableStoreHeader
) == EfiValid
) {
3705 if (!NeedConvertNormalToAuth
) {
3706 mVariableModuleGlobal
->VariableGlobal
.HobVariableBase
= (EFI_PHYSICAL_ADDRESS
) (UINTN
) AllocateRuntimeCopyPool ((UINTN
) VariableStoreLength
, (VOID
*) VariableStoreHeader
);
3708 mVariableModuleGlobal
->VariableGlobal
.HobVariableBase
= (EFI_PHYSICAL_ADDRESS
) (UINTN
) ConvertNormalVarStorageToAuthVarStorage ((VOID
*) VariableStoreHeader
);
3710 if (mVariableModuleGlobal
->VariableGlobal
.HobVariableBase
== 0) {
3711 return EFI_OUT_OF_RESOURCES
;
3714 DEBUG ((EFI_D_ERROR
, "HOB Variable Store header is corrupted!\n"));
3722 Initializes variable store area for non-volatile and volatile variable.
3724 @retval EFI_SUCCESS Function successfully executed.
3725 @retval EFI_OUT_OF_RESOURCES Fail to allocate enough memory resource.
3729 VariableCommonInitialize (
3734 VARIABLE_STORE_HEADER
*VolatileVariableStore
;
3736 EFI_GUID
*VariableGuid
;
3739 // Allocate runtime memory for variable driver global structure.
3741 mVariableModuleGlobal
= AllocateRuntimeZeroPool (sizeof (VARIABLE_MODULE_GLOBAL
));
3742 if (mVariableModuleGlobal
== NULL
) {
3743 return EFI_OUT_OF_RESOURCES
;
3746 InitializeLock (&mVariableModuleGlobal
->VariableGlobal
.VariableServicesLock
, TPL_NOTIFY
);
3749 // Init non-volatile variable store.
3751 Status
= InitNonVolatileVariableStore ();
3752 if (EFI_ERROR (Status
)) {
3753 FreePool (mVariableModuleGlobal
);
3758 // mVariableModuleGlobal->VariableGlobal.AuthFormat
3759 // has been initialized in InitNonVolatileVariableStore().
3761 if (mVariableModuleGlobal
->VariableGlobal
.AuthFormat
) {
3762 DEBUG ((EFI_D_INFO
, "Variable driver will work with auth variable format!\n"));
3764 // Set AuthSupport to FALSE first, VariableWriteServiceInitialize() will initialize it.
3766 mVariableModuleGlobal
->VariableGlobal
.AuthSupport
= FALSE
;
3767 VariableGuid
= &gEfiAuthenticatedVariableGuid
;
3769 DEBUG ((EFI_D_INFO
, "Variable driver will work without auth variable support!\n"));
3770 mVariableModuleGlobal
->VariableGlobal
.AuthSupport
= FALSE
;
3771 VariableGuid
= &gEfiVariableGuid
;
3775 // Get HOB variable store.
3777 Status
= GetHobVariableStore (VariableGuid
);
3778 if (EFI_ERROR (Status
)) {
3779 if (mNvFvHeaderCache
!= NULL
) {
3780 FreePool (mNvFvHeaderCache
);
3782 FreePool (mVariableModuleGlobal
);
3786 mVariableModuleGlobal
->MaxVolatileVariableSize
= ((PcdGet32 (PcdMaxVolatileVariableSize
) != 0) ?
3787 PcdGet32 (PcdMaxVolatileVariableSize
) :
3788 mVariableModuleGlobal
->MaxVariableSize
3791 // Allocate memory for volatile variable store, note that there is a scratch space to store scratch data.
3793 ScratchSize
= GetMaxVariableSize ();
3794 mVariableModuleGlobal
->ScratchBufferSize
= ScratchSize
;
3795 VolatileVariableStore
= AllocateRuntimePool (PcdGet32 (PcdVariableStoreSize
) + ScratchSize
);
3796 if (VolatileVariableStore
== NULL
) {
3797 if (mVariableModuleGlobal
->VariableGlobal
.HobVariableBase
!= 0) {
3798 FreePool ((VOID
*) (UINTN
) mVariableModuleGlobal
->VariableGlobal
.HobVariableBase
);
3800 if (mNvFvHeaderCache
!= NULL
) {
3801 FreePool (mNvFvHeaderCache
);
3803 FreePool (mVariableModuleGlobal
);
3804 return EFI_OUT_OF_RESOURCES
;
3807 SetMem (VolatileVariableStore
, PcdGet32 (PcdVariableStoreSize
) + ScratchSize
, 0xff);
3810 // Initialize Variable Specific Data.
3812 mVariableModuleGlobal
->VariableGlobal
.VolatileVariableBase
= (EFI_PHYSICAL_ADDRESS
) (UINTN
) VolatileVariableStore
;
3813 mVariableModuleGlobal
->VolatileLastVariableOffset
= (UINTN
) GetStartPointer (VolatileVariableStore
) - (UINTN
) VolatileVariableStore
;
3815 CopyGuid (&VolatileVariableStore
->Signature
, VariableGuid
);
3816 VolatileVariableStore
->Size
= PcdGet32 (PcdVariableStoreSize
);
3817 VolatileVariableStore
->Format
= VARIABLE_STORE_FORMATTED
;
3818 VolatileVariableStore
->State
= VARIABLE_STORE_HEALTHY
;
3819 VolatileVariableStore
->Reserved
= 0;
3820 VolatileVariableStore
->Reserved1
= 0;
3827 Get the proper fvb handle and/or fvb protocol by the given Flash address.
3829 @param[in] Address The Flash address.
3830 @param[out] FvbHandle In output, if it is not NULL, it points to the proper FVB handle.
3831 @param[out] FvbProtocol In output, if it is not NULL, it points to the proper FVB protocol.
3835 GetFvbInfoByAddress (
3836 IN EFI_PHYSICAL_ADDRESS Address
,
3837 OUT EFI_HANDLE
*FvbHandle OPTIONAL
,
3838 OUT EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
**FvbProtocol OPTIONAL
3842 EFI_HANDLE
*HandleBuffer
;
3845 EFI_PHYSICAL_ADDRESS FvbBaseAddress
;
3846 EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*Fvb
;
3847 EFI_FVB_ATTRIBUTES_2 Attributes
;
3849 UINTN NumberOfBlocks
;
3851 HandleBuffer
= NULL
;
3853 // Get all FVB handles.
3855 Status
= GetFvbCountAndBuffer (&HandleCount
, &HandleBuffer
);
3856 if (EFI_ERROR (Status
)) {
3857 return EFI_NOT_FOUND
;
3861 // Get the FVB to access variable store.
3864 for (Index
= 0; Index
< HandleCount
; Index
+= 1, Status
= EFI_NOT_FOUND
, Fvb
= NULL
) {
3865 Status
= GetFvbByHandle (HandleBuffer
[Index
], &Fvb
);
3866 if (EFI_ERROR (Status
)) {
3867 Status
= EFI_NOT_FOUND
;
3872 // Ensure this FVB protocol supported Write operation.
3874 Status
= Fvb
->GetAttributes (Fvb
, &Attributes
);
3875 if (EFI_ERROR (Status
) || ((Attributes
& EFI_FVB2_WRITE_STATUS
) == 0)) {
3880 // Compare the address and select the right one.
3882 Status
= Fvb
->GetPhysicalAddress (Fvb
, &FvbBaseAddress
);
3883 if (EFI_ERROR (Status
)) {
3888 // Assume one FVB has one type of BlockSize.
3890 Status
= Fvb
->GetBlockSize (Fvb
, 0, &BlockSize
, &NumberOfBlocks
);
3891 if (EFI_ERROR (Status
)) {
3895 if ((Address
>= FvbBaseAddress
) && (Address
< (FvbBaseAddress
+ BlockSize
* NumberOfBlocks
))) {
3896 if (FvbHandle
!= NULL
) {
3897 *FvbHandle
= HandleBuffer
[Index
];
3899 if (FvbProtocol
!= NULL
) {
3902 Status
= EFI_SUCCESS
;
3906 FreePool (HandleBuffer
);
3909 Status
= EFI_NOT_FOUND
;