OpenCore  1.0.4
OpenCore Bootloader
Loading...
Searching...
No Matches
Variable.c
Go to the documentation of this file.
1
28#include "Variable.h"
29#include "VariableNonVolatile.h"
30#include "VariableParsing.h"
32
33#define EFI_VARIABLE_APPLE_BIT 0x80000000
34
36
41VARIABLE_STORE_HEADER *mNvVariableCache = NULL;
42
46EFI_FIRMWARE_VOLUME_HEADER *mNvFvHeaderCache = NULL;
47
51VARIABLE_INFO_ENTRY *gVariableInfo = NULL;
52
56BOOLEAN mEndOfDxe = FALSE;
57
62VAR_CHECK_REQUEST_SOURCE mRequestSource = VarCheckFromUntrusted;
63
64//
65// It will record the current boot error flag before EndOfDxe.
66//
67VAR_ERROR_FLAG mCurrentBootVarErrFlag = VAR_ERROR_FLAG_NO_ERROR;
68
69VARIABLE_ENTRY_PROPERTY mVariableEntryProperty[] = {
70 {
71 &gEdkiiVarErrorFlagGuid,
72 VAR_ERROR_FLAG_NAME,
73 {
74 VAR_CHECK_VARIABLE_PROPERTY_REVISION,
75 VAR_CHECK_VARIABLE_PROPERTY_READ_ONLY,
76 VARIABLE_ATTRIBUTE_NV_BS_RT,
77 sizeof (VAR_ERROR_FLAG),
78 sizeof (VAR_ERROR_FLAG)
79 }
80 },
81};
82
83AUTH_VAR_LIB_CONTEXT_IN mAuthContextIn = {
84 AUTH_VAR_LIB_CONTEXT_IN_STRUCT_VERSION,
85 //
86 // StructSize, TO BE FILLED
87 //
88 0,
89 //
90 // MaxAuthVariableSize, TO BE FILLED
91 //
92 0,
99};
100
101AUTH_VAR_LIB_CONTEXT_OUT mAuthContextOut;
102
124EFI_STATUS
126 IN VARIABLE_GLOBAL *Global,
127 IN BOOLEAN Volatile,
128 IN BOOLEAN SetByIndex,
129 IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *Fvb,
130 IN UINTN DataPtrIndex,
131 IN UINT32 DataSize,
132 IN UINT8 *Buffer
133 )
134{
135 EFI_FV_BLOCK_MAP_ENTRY *PtrBlockMapEntry;
136 UINTN BlockIndex2;
137 UINTN LinearOffset;
138 UINTN CurrWriteSize;
139 UINTN CurrWritePtr;
140 UINT8 *CurrBuffer;
141 EFI_LBA LbaNumber;
142 UINTN Size;
143 VARIABLE_STORE_HEADER *VolatileBase;
144 EFI_PHYSICAL_ADDRESS FvVolHdr;
145 EFI_PHYSICAL_ADDRESS DataPtr;
146 EFI_STATUS Status;
147
148 FvVolHdr = 0;
149 DataPtr = DataPtrIndex;
150
151 //
152 // Check if the Data is Volatile.
153 //
155 if (Fvb == NULL) {
156 return EFI_UNSUPPORTED;
157 }
158
159 Status = Fvb->GetPhysicalAddress (Fvb, &FvVolHdr);
160 ASSERT_EFI_ERROR (Status);
161
162 //
163 // Data Pointer should point to the actual Address where data is to be
164 // written.
165 //
166 if (SetByIndex) {
168 }
169
170 if ((DataPtr + DataSize) > (FvVolHdr + mNvFvHeaderCache->FvLength)) {
171 return EFI_OUT_OF_RESOURCES;
172 }
173 } else {
174 //
175 // Data Pointer should point to the actual Address where data is to be
176 // written.
177 //
178 if (Volatile) {
179 VolatileBase = (VARIABLE_STORE_HEADER *)((UINTN)mVariableModuleGlobal->VariableGlobal.VolatileVariableBase);
180 if (SetByIndex) {
182 }
183
184 if ((DataPtr + DataSize) > ((UINTN)VolatileBase + VolatileBase->Size)) {
185 return EFI_OUT_OF_RESOURCES;
186 }
187 } else {
188 //
189 // Emulated non-volatile variable mode.
190 //
191 if (SetByIndex) {
192 DataPtr += (UINTN)mNvVariableCache;
193 }
194
195 if ((DataPtr + DataSize) > ((UINTN)mNvVariableCache + mNvVariableCache->Size)) {
196 return EFI_OUT_OF_RESOURCES;
197 }
198 }
199
200 //
201 // If Volatile/Emulated Non-volatile Variable just do a simple mem copy.
202 //
203 CopyMem ((UINT8 *)(UINTN)DataPtr, Buffer, DataSize);
204 return EFI_SUCCESS;
205 }
206
207 //
208 // If we are here we are dealing with Non-Volatile Variables.
209 //
210 LinearOffset = (UINTN)FvVolHdr;
211 CurrWritePtr = (UINTN)DataPtr;
212 CurrWriteSize = DataSize;
213 CurrBuffer = Buffer;
214 LbaNumber = 0;
215
216 if (CurrWritePtr < LinearOffset) {
217 return EFI_INVALID_PARAMETER;
218 }
219
220 for (PtrBlockMapEntry = mNvFvHeaderCache->BlockMap; PtrBlockMapEntry->NumBlocks != 0; PtrBlockMapEntry++) {
221 for (BlockIndex2 = 0; BlockIndex2 < PtrBlockMapEntry->NumBlocks; BlockIndex2++) {
222 //
223 // Check to see if the Variable Writes are spanning through multiple
224 // blocks.
225 //
226 if ((CurrWritePtr >= LinearOffset) && (CurrWritePtr < LinearOffset + PtrBlockMapEntry->Length)) {
227 if ((CurrWritePtr + CurrWriteSize) <= (LinearOffset + PtrBlockMapEntry->Length)) {
228 Status = Fvb->Write (
229 Fvb,
230 LbaNumber,
231 (UINTN)(CurrWritePtr - LinearOffset),
232 &CurrWriteSize,
233 CurrBuffer
234 );
235 return Status;
236 } else {
237 Size = (UINT32)(LinearOffset + PtrBlockMapEntry->Length - CurrWritePtr);
238 Status = Fvb->Write (
239 Fvb,
240 LbaNumber,
241 (UINTN)(CurrWritePtr - LinearOffset),
242 &Size,
243 CurrBuffer
244 );
245 if (EFI_ERROR (Status)) {
246 return Status;
247 }
248
249 CurrWritePtr = LinearOffset + PtrBlockMapEntry->Length;
250 CurrBuffer = CurrBuffer + Size;
251 CurrWriteSize = CurrWriteSize - Size;
252 }
253 }
254
255 LinearOffset += PtrBlockMapEntry->Length;
256 LbaNumber++;
257 }
258 }
259
260 return EFI_SUCCESS;
261}
262
273VOID
275 IN VAR_ERROR_FLAG Flag,
276 IN CHAR16 *VariableName,
277 IN EFI_GUID *VendorGuid,
278 IN UINT32 Attributes,
279 IN UINTN VariableSize
280 )
281{
282 EFI_STATUS Status;
283 VARIABLE_POINTER_TRACK Variable;
284 VAR_ERROR_FLAG *VarErrFlag;
285 VAR_ERROR_FLAG TempFlag;
286
287 DEBUG_CODE_BEGIN ();
288 DEBUG ((DEBUG_ERROR, "RecordVarErrorFlag (0x%02x) %s:%g - 0x%08x - 0x%x\n", Flag, VariableName, VendorGuid, Attributes, VariableSize));
289 if (Flag == VAR_ERROR_FLAG_SYSTEM_ERROR) {
290 if (AtRuntime ()) {
291 DEBUG ((DEBUG_ERROR, "CommonRuntimeVariableSpace = 0x%x - CommonVariableTotalSize = 0x%x\n", mVariableModuleGlobal->CommonRuntimeVariableSpace, mVariableModuleGlobal->CommonVariableTotalSize));
292 } else {
293 DEBUG ((DEBUG_ERROR, "CommonVariableSpace = 0x%x - CommonVariableTotalSize = 0x%x\n", mVariableModuleGlobal->CommonVariableSpace, mVariableModuleGlobal->CommonVariableTotalSize));
294 }
295 } else {
296 DEBUG ((DEBUG_ERROR, "CommonMaxUserVariableSpace = 0x%x - CommonUserVariableTotalSize = 0x%x\n", mVariableModuleGlobal->CommonMaxUserVariableSpace, mVariableModuleGlobal->CommonUserVariableTotalSize));
297 }
298
299 DEBUG_CODE_END ();
300
301 if (!mEndOfDxe) {
302 //
303 // Before EndOfDxe, just record the current boot variable error flag to local variable,
304 // and leave the variable error flag in NV flash as the last boot variable error flag.
305 // After EndOfDxe in InitializeVarErrorFlag (), the variable error flag in NV flash
306 // will be initialized to this local current boot variable error flag.
307 //
309 return;
310 }
311
312 //
313 // Record error flag (it should have be initialized).
314 //
315 Status = FindVariable (
316 VAR_ERROR_FLAG_NAME,
317 &gEdkiiVarErrorFlagGuid,
318 &Variable,
320 FALSE
321 );
322 if (!EFI_ERROR (Status)) {
323 VarErrFlag = (VAR_ERROR_FLAG *)GetVariableDataPtr (Variable.CurrPtr, mVariableModuleGlobal->VariableGlobal.AuthFormat);
324 TempFlag = *VarErrFlag;
325 TempFlag &= Flag;
326 if (TempFlag == *VarErrFlag) {
327 return;
328 }
329
330 Status = UpdateVariableStore (
332 FALSE,
333 FALSE,
336 sizeof (TempFlag),
337 &TempFlag
338 );
339 if (!EFI_ERROR (Status)) {
340 //
341 // Update the data in NV cache.
342 //
343 *VarErrFlag = TempFlag;
346 0,
347 mNvVariableCache->Size
348 );
349 ASSERT_EFI_ERROR (Status);
350 }
351 }
352}
353
363VOID
365 VOID
366 )
367{
368 EFI_STATUS Status;
369 VARIABLE_POINTER_TRACK Variable;
370 VAR_ERROR_FLAG Flag;
371 VAR_ERROR_FLAG VarErrFlag;
372
373 if (!mEndOfDxe) {
374 return;
375 }
376
378 DEBUG ((DEBUG_INFO, "Initialize variable error flag (%02x)\n", Flag));
379
380 Status = FindVariable (
381 VAR_ERROR_FLAG_NAME,
382 &gEdkiiVarErrorFlagGuid,
383 &Variable,
385 FALSE
386 );
387 if (!EFI_ERROR (Status)) {
388 VarErrFlag = *((VAR_ERROR_FLAG *)GetVariableDataPtr (Variable.CurrPtr, mVariableModuleGlobal->VariableGlobal.AuthFormat));
389 if (VarErrFlag == Flag) {
390 return;
391 }
392 }
393
395 VAR_ERROR_FLAG_NAME,
396 &gEdkiiVarErrorFlagGuid,
397 &Flag,
398 sizeof (Flag),
399 VARIABLE_ATTRIBUTE_NV_BS_RT,
400 0,
401 0,
402 &Variable,
403 NULL
404 );
405}
406
416BOOLEAN
418 IN VARIABLE_HEADER *Variable
419 )
420{
421 VAR_CHECK_VARIABLE_PROPERTY Property;
422
423 //
424 // Only after End Of Dxe, the variables belong to system variable are fixed.
425 // If PcdMaxUserNvStorageVariableSize is 0, it means user variable share the same NV storage with system variable,
426 // then no need to check if the variable is user variable or not specially.
427 //
429 if (VarCheckLibVariablePropertyGet (
432 &Property
433 ) == EFI_NOT_FOUND)
434 {
435 return TRUE;
436 }
437 }
438
439 return FALSE;
440}
441
446VOID
448 VOID
449 )
450{
451 VARIABLE_HEADER *Variable;
452 VARIABLE_HEADER *NextVariable;
453 UINTN VariableSize;
454 VAR_CHECK_VARIABLE_PROPERTY Property;
455
456 //
457 // Only after End Of Dxe, the variables belong to system variable are fixed.
458 // If PcdMaxUserNvStorageVariableSize is 0, it means user variable share the same NV storage with system variable,
459 // then no need to calculate the common user variable total size specially.
460 //
465 VariableSize = (UINTN)NextVariable - (UINTN)Variable;
466 if ((Variable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) != EFI_VARIABLE_HARDWARE_ERROR_RECORD) {
467 if (VarCheckLibVariablePropertyGet (
470 &Property
471 ) == EFI_NOT_FOUND)
472 {
473 //
474 // No property, it is user variable.
475 //
477 }
478 }
479
480 Variable = NextVariable;
481 }
482 }
483}
484
489VOID
491 VOID
492 )
493{
494 if (!mEndOfDxe) {
495 return;
496 }
497
500}
501
519EFI_STATUS
521 IN EFI_PHYSICAL_ADDRESS VariableBase,
522 OUT UINTN *LastVariableOffset,
523 IN BOOLEAN IsVolatile,
524 IN OUT VARIABLE_POINTER_TRACK *UpdatingPtrTrack,
525 IN VARIABLE_HEADER *NewVariable,
526 IN UINTN NewVariableSize
527 )
528{
529 VARIABLE_HEADER *Variable;
530 VARIABLE_HEADER *AddedVariable;
531 VARIABLE_HEADER *NextVariable;
532 VARIABLE_HEADER *NextAddedVariable;
533 VARIABLE_STORE_HEADER *VariableStoreHeader;
534 UINT8 *ValidBuffer;
535 UINTN MaximumBufferSize;
536 UINTN VariableSize;
537 UINTN NameSize;
538 UINT8 *CurrPtr;
539 VOID *Point0;
540 VOID *Point1;
541 BOOLEAN FoundAdded;
542 EFI_STATUS Status;
543 EFI_STATUS DoneStatus;
544 UINTN CommonVariableTotalSize;
545 UINTN CommonUserVariableTotalSize;
546 UINTN HwErrVariableTotalSize;
547 VARIABLE_HEADER *UpdatingVariable;
548 VARIABLE_HEADER *UpdatingInDeletedTransition;
549 BOOLEAN AuthFormat;
550
552 UpdatingVariable = NULL;
553 UpdatingInDeletedTransition = NULL;
554 if (UpdatingPtrTrack != NULL) {
555 UpdatingVariable = UpdatingPtrTrack->CurrPtr;
556 UpdatingInDeletedTransition = UpdatingPtrTrack->InDeletedTransitionPtr;
557 }
558
559 VariableStoreHeader = (VARIABLE_STORE_HEADER *)((UINTN)VariableBase);
560
561 CommonVariableTotalSize = 0;
562 CommonUserVariableTotalSize = 0;
563 HwErrVariableTotalSize = 0;
564
566 //
567 // Start Pointers for the variable.
568 //
569 Variable = GetStartPointer (VariableStoreHeader);
570 MaximumBufferSize = sizeof (VARIABLE_STORE_HEADER);
571
572 while (IsValidVariableHeader (Variable, GetEndPointer (VariableStoreHeader))) {
573 NextVariable = GetNextVariablePtr (Variable, AuthFormat);
574 if (((Variable->State == VAR_ADDED) || (Variable->State == (VAR_IN_DELETED_TRANSITION & VAR_ADDED))) &&
575 (Variable != UpdatingVariable) &&
576 (Variable != UpdatingInDeletedTransition)
577 )
578 {
579 VariableSize = (UINTN)NextVariable - (UINTN)Variable;
580 MaximumBufferSize += VariableSize;
581 }
582
583 Variable = NextVariable;
584 }
585
586 if (NewVariable != NULL) {
587 //
588 // Add the new variable size.
589 //
590 MaximumBufferSize += NewVariableSize;
591 }
592
593 //
594 // Reserve the 1 Bytes with Oxff to identify the
595 // end of the variable buffer.
596 //
597 MaximumBufferSize += 1;
598 ValidBuffer = AllocatePool (MaximumBufferSize);
599 if (ValidBuffer == NULL) {
600 return EFI_OUT_OF_RESOURCES;
601 }
602 } else {
603 //
604 // For NV variable reclaim, don't allocate pool here and just use mNvVariableCache
605 // as the buffer to reduce SMRAM consumption for SMM variable driver.
606 //
607 MaximumBufferSize = mNvVariableCache->Size;
608 ValidBuffer = (UINT8 *)mNvVariableCache;
609 }
610
611 SetMem (ValidBuffer, MaximumBufferSize, 0xff);
612
613 //
614 // Copy variable store header.
615 //
616 CopyMem (ValidBuffer, VariableStoreHeader, sizeof (VARIABLE_STORE_HEADER));
617 CurrPtr = (UINT8 *)GetStartPointer ((VARIABLE_STORE_HEADER *)ValidBuffer);
618
619 //
620 // Reinstall all ADDED variables as long as they are not identical to Updating Variable.
621 //
622 Variable = GetStartPointer (VariableStoreHeader);
623 while (IsValidVariableHeader (Variable, GetEndPointer (VariableStoreHeader))) {
624 NextVariable = GetNextVariablePtr (Variable, AuthFormat);
625 if ((Variable != UpdatingVariable) && (Variable->State == VAR_ADDED)) {
626 VariableSize = (UINTN)NextVariable - (UINTN)Variable;
627 CopyMem (CurrPtr, (UINT8 *)Variable, VariableSize);
628 CurrPtr += VariableSize;
629 if ((!IsVolatile) && ((Variable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == EFI_VARIABLE_HARDWARE_ERROR_RECORD)) {
630 HwErrVariableTotalSize += VariableSize;
631 } else if ((!IsVolatile) && ((Variable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) != EFI_VARIABLE_HARDWARE_ERROR_RECORD)) {
632 CommonVariableTotalSize += VariableSize;
633 if (IsUserVariable (Variable)) {
634 CommonUserVariableTotalSize += VariableSize;
635 }
636 }
637 }
638
639 Variable = NextVariable;
640 }
641
642 //
643 // Reinstall all in delete transition variables.
644 //
645 Variable = GetStartPointer (VariableStoreHeader);
646 while (IsValidVariableHeader (Variable, GetEndPointer (VariableStoreHeader))) {
647 NextVariable = GetNextVariablePtr (Variable, AuthFormat);
648 if ((Variable != UpdatingVariable) && (Variable != UpdatingInDeletedTransition) && (Variable->State == (VAR_IN_DELETED_TRANSITION & VAR_ADDED))) {
649 //
650 // Buffer has cached all ADDED variable.
651 // Per IN_DELETED variable, we have to guarantee that
652 // no ADDED one in previous buffer.
653 //
654
655 FoundAdded = FALSE;
656 AddedVariable = GetStartPointer ((VARIABLE_STORE_HEADER *)ValidBuffer);
657 while (IsValidVariableHeader (AddedVariable, GetEndPointer ((VARIABLE_STORE_HEADER *)ValidBuffer))) {
658 NextAddedVariable = GetNextVariablePtr (AddedVariable, AuthFormat);
659 NameSize = NameSizeOfVariable (AddedVariable, AuthFormat);
660 if (CompareGuid (
661 GetVendorGuidPtr (AddedVariable, AuthFormat),
662 GetVendorGuidPtr (Variable, AuthFormat)
663 ) && (NameSize == NameSizeOfVariable (Variable, AuthFormat)))
664 {
665 Point0 = (VOID *)GetVariableNamePtr (AddedVariable, AuthFormat);
666 Point1 = (VOID *)GetVariableNamePtr (Variable, AuthFormat);
667 if (CompareMem (Point0, Point1, NameSize) == 0) {
668 FoundAdded = TRUE;
669 break;
670 }
671 }
672
673 AddedVariable = NextAddedVariable;
674 }
675
676 if (!FoundAdded) {
677 //
678 // Promote VAR_IN_DELETED_TRANSITION to VAR_ADDED.
679 //
680 VariableSize = (UINTN)NextVariable - (UINTN)Variable;
681 CopyMem (CurrPtr, (UINT8 *)Variable, VariableSize);
682 ((VARIABLE_HEADER *)CurrPtr)->State = VAR_ADDED;
683 CurrPtr += VariableSize;
684 if ((!IsVolatile) && ((Variable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == EFI_VARIABLE_HARDWARE_ERROR_RECORD)) {
685 HwErrVariableTotalSize += VariableSize;
686 } else if ((!IsVolatile) && ((Variable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) != EFI_VARIABLE_HARDWARE_ERROR_RECORD)) {
687 CommonVariableTotalSize += VariableSize;
688 if (IsUserVariable (Variable)) {
689 CommonUserVariableTotalSize += VariableSize;
690 }
691 }
692 }
693 }
694
695 Variable = NextVariable;
696 }
697
698 //
699 // Install the new variable if it is not NULL.
700 //
701 if (NewVariable != NULL) {
702 if (((UINTN)CurrPtr - (UINTN)ValidBuffer) + NewVariableSize > VariableStoreHeader->Size) {
703 //
704 // No enough space to store the new variable.
705 //
706 Status = EFI_OUT_OF_RESOURCES;
707 goto Done;
708 }
709
710 if (!IsVolatile) {
711 if ((NewVariable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == EFI_VARIABLE_HARDWARE_ERROR_RECORD) {
712 HwErrVariableTotalSize += NewVariableSize;
713 } else if ((NewVariable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) != EFI_VARIABLE_HARDWARE_ERROR_RECORD) {
714 CommonVariableTotalSize += NewVariableSize;
715 if (IsUserVariable (NewVariable)) {
716 CommonUserVariableTotalSize += NewVariableSize;
717 }
718 }
719
720 if ((HwErrVariableTotalSize > PcdGet32 (PcdHwErrStorageSize)) ||
721 (CommonVariableTotalSize > mVariableModuleGlobal->CommonVariableSpace) ||
722 (CommonUserVariableTotalSize > mVariableModuleGlobal->CommonMaxUserVariableSpace))
723 {
724 //
725 // No enough space to store the new variable by NV or NV+HR attribute.
726 //
727 Status = EFI_OUT_OF_RESOURCES;
728 goto Done;
729 }
730 }
731
732 CopyMem (CurrPtr, (UINT8 *)NewVariable, NewVariableSize);
733 ((VARIABLE_HEADER *)CurrPtr)->State = VAR_ADDED;
734 if (UpdatingVariable != NULL) {
735 UpdatingPtrTrack->CurrPtr = (VARIABLE_HEADER *)((UINTN)UpdatingPtrTrack->StartPtr + ((UINTN)CurrPtr - (UINTN)GetStartPointer ((VARIABLE_STORE_HEADER *)ValidBuffer)));
736 UpdatingPtrTrack->InDeletedTransitionPtr = NULL;
737 }
738
739 CurrPtr += NewVariableSize;
740 }
741
743 //
744 // If volatile/emulated non-volatile variable store, just copy valid buffer.
745 //
746 SetMem ((UINT8 *)(UINTN)VariableBase, VariableStoreHeader->Size, 0xff);
747 CopyMem ((UINT8 *)(UINTN)VariableBase, ValidBuffer, (UINTN)CurrPtr - (UINTN)ValidBuffer);
748 *LastVariableOffset = (UINTN)CurrPtr - (UINTN)ValidBuffer;
749 if (!IsVolatile) {
750 //
751 // Emulated non-volatile variable mode.
752 //
753 mVariableModuleGlobal->HwErrVariableTotalSize = HwErrVariableTotalSize;
754 mVariableModuleGlobal->CommonVariableTotalSize = CommonVariableTotalSize;
755 mVariableModuleGlobal->CommonUserVariableTotalSize = CommonUserVariableTotalSize;
756 }
757
758 Status = EFI_SUCCESS;
759 } else {
760 //
761 // If non-volatile variable store, perform FTW here.
762 //
763 Status = FtwVariableSpace (
764 VariableBase,
765 (VARIABLE_STORE_HEADER *)ValidBuffer
766 );
767 if (!EFI_ERROR (Status)) {
768 *LastVariableOffset = (UINTN)CurrPtr - (UINTN)ValidBuffer;
769 mVariableModuleGlobal->HwErrVariableTotalSize = HwErrVariableTotalSize;
770 mVariableModuleGlobal->CommonVariableTotalSize = CommonVariableTotalSize;
771 mVariableModuleGlobal->CommonUserVariableTotalSize = CommonUserVariableTotalSize;
772 } else {
776 Variable = GetStartPointer ((VARIABLE_STORE_HEADER *)(UINTN)VariableBase);
777 while (IsValidVariableHeader (Variable, GetEndPointer ((VARIABLE_STORE_HEADER *)(UINTN)VariableBase))) {
778 NextVariable = GetNextVariablePtr (Variable, AuthFormat);
779 VariableSize = (UINTN)NextVariable - (UINTN)Variable;
780 if ((Variable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == EFI_VARIABLE_HARDWARE_ERROR_RECORD) {
782 } else if ((Variable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) != EFI_VARIABLE_HARDWARE_ERROR_RECORD) {
784 if (IsUserVariable (Variable)) {
786 }
787 }
788
789 Variable = NextVariable;
790 }
791
792 *LastVariableOffset = (UINTN)Variable - (UINTN)VariableBase;
793 }
794 }
795
796Done:
797 DoneStatus = EFI_SUCCESS;
801 0,
802 VariableStoreHeader->Size
803 );
804 ASSERT_EFI_ERROR (DoneStatus);
805 FreePool (ValidBuffer);
806 } else {
807 //
808 // For NV variable reclaim, we use mNvVariableCache as the buffer, so copy the data back.
809 //
810 CopyMem (mNvVariableCache, (UINT8 *)(UINTN)VariableBase, VariableStoreHeader->Size);
813 0,
814 VariableStoreHeader->Size
815 );
816 ASSERT_EFI_ERROR (DoneStatus);
817 }
818
819 if (!EFI_ERROR (Status) && EFI_ERROR (DoneStatus)) {
820 Status = DoneStatus;
821 }
822
823 return Status;
824}
825
852EFI_STATUS
854 IN CHAR16 *VariableName,
855 IN EFI_GUID *VendorGuid,
856 OUT VARIABLE_POINTER_TRACK *PtrTrack,
857 IN VARIABLE_GLOBAL *Global,
858 IN BOOLEAN IgnoreRtCheck
859 )
860{
861 EFI_STATUS Status;
862 VARIABLE_STORE_HEADER *VariableStoreHeader[VariableStoreTypeMax];
864
865 if ((VariableName[0] != 0) && (VendorGuid == NULL)) {
866 return EFI_INVALID_PARAMETER;
867 }
868
869 //
870 // 0: Volatile, 1: HOB, 2: Non-Volatile.
871 // The index and attributes mapping must be kept in this order as RuntimeServiceGetNextVariableName
872 // make use of this mapping to implement search algorithm.
873 //
874 VariableStoreHeader[VariableStoreTypeVolatile] = (VARIABLE_STORE_HEADER *)(UINTN)Global->VolatileVariableBase;
875 VariableStoreHeader[VariableStoreTypeHob] = (VARIABLE_STORE_HEADER *)(UINTN)Global->HobVariableBase;
876 VariableStoreHeader[VariableStoreTypeNv] = mNvVariableCache;
877
878 //
879 // Find the variable by walk through HOB, volatile and non-volatile variable store.
880 //
881 for (Type = (VARIABLE_STORE_TYPE)0; Type < VariableStoreTypeMax; Type++) {
882 if (VariableStoreHeader[Type] == NULL) {
883 continue;
884 }
885
886 PtrTrack->StartPtr = GetStartPointer (VariableStoreHeader[Type]);
887 PtrTrack->EndPtr = GetEndPointer (VariableStoreHeader[Type]);
888 PtrTrack->Volatile = (BOOLEAN)(Type == VariableStoreTypeVolatile);
889
890 Status = FindVariableEx (
891 VariableName,
892 VendorGuid,
893 IgnoreRtCheck,
894 PtrTrack,
896 );
897 if (!EFI_ERROR (Status)) {
898 return Status;
899 }
900 }
901
902 return EFI_NOT_FOUND;
903}
904
931UINTN
933 IN CHAR8 *SupportedLang,
934 IN CHAR8 *Lang,
935 IN BOOLEAN Iso639Language
936 )
937{
938 UINTN Index;
939 UINTN CompareLength;
940 UINTN LanguageLength;
941
942 if (Iso639Language) {
943 CompareLength = ISO_639_2_ENTRY_SIZE;
944 for (Index = 0; Index < AsciiStrLen (SupportedLang); Index += CompareLength) {
945 if (AsciiStrnCmp (Lang, SupportedLang + Index, CompareLength) == 0) {
946 //
947 // Successfully find the index of Lang string in SupportedLang string.
948 //
949 Index = Index / CompareLength;
950 return Index;
951 }
952 }
953
954 ASSERT (FALSE);
955 return 0;
956 } else {
957 //
958 // Compare RFC4646 language code
959 //
960 Index = 0;
961 for (LanguageLength = 0; Lang[LanguageLength] != '\0'; LanguageLength++) {
962 }
963
964 for (Index = 0; *SupportedLang != '\0'; Index++, SupportedLang += CompareLength) {
965 //
966 // Skip ';' characters in SupportedLang
967 //
968 for ( ; *SupportedLang != '\0' && *SupportedLang == ';'; SupportedLang++) {
969 }
970
971 //
972 // Determine the length of the next language code in SupportedLang
973 //
974 for (CompareLength = 0; SupportedLang[CompareLength] != '\0' && SupportedLang[CompareLength] != ';'; CompareLength++) {
975 }
976
977 if ((CompareLength == LanguageLength) &&
978 (AsciiStrnCmp (Lang, SupportedLang, CompareLength) == 0))
979 {
980 //
981 // Successfully find the index of Lang string in SupportedLang string.
982 //
983 return Index;
984 }
985 }
986
987 ASSERT (FALSE);
988 return 0;
989 }
990}
991
1018CHAR8 *
1020 IN CHAR8 *SupportedLang,
1021 IN UINTN Index,
1022 IN BOOLEAN Iso639Language
1023 )
1024{
1025 UINTN SubIndex;
1026 UINTN CompareLength;
1027 CHAR8 *Supported;
1028
1029 SubIndex = 0;
1030 Supported = SupportedLang;
1031 if (Iso639Language) {
1032 //
1033 // According to the index of Lang string in SupportedLang string to get the language.
1034 // This code will be invoked in RUNTIME, therefore there is not a memory allocate/free operation.
1035 // In driver entry, it pre-allocates a runtime attribute memory to accommodate this string.
1036 //
1037 CompareLength = ISO_639_2_ENTRY_SIZE;
1038 mVariableModuleGlobal->Lang[CompareLength] = '\0';
1039 return CopyMem (mVariableModuleGlobal->Lang, SupportedLang + Index * CompareLength, CompareLength);
1040 } else {
1041 while (TRUE) {
1042 //
1043 // Take semicolon as delimitation, sequentially traverse supported language codes.
1044 //
1045 for (CompareLength = 0; *Supported != ';' && *Supported != '\0'; CompareLength++) {
1046 Supported++;
1047 }
1048
1049 if ((*Supported == '\0') && (SubIndex != Index)) {
1050 //
1051 // Have completed the traverse, but not find corrsponding string.
1052 // This case is not allowed to happen.
1053 //
1054 ASSERT (FALSE);
1055 return NULL;
1056 }
1057
1058 if (SubIndex == Index) {
1059 //
1060 // According to the index of Lang string in SupportedLang string to get the language.
1061 // As this code will be invoked in RUNTIME, therefore there is not memory allocate/free operation.
1062 // In driver entry, it pre-allocates a runtime attribute memory to accommodate this string.
1063 //
1064 mVariableModuleGlobal->PlatformLang[CompareLength] = '\0';
1065 return CopyMem (mVariableModuleGlobal->PlatformLang, Supported - CompareLength, CompareLength);
1066 }
1067
1068 SubIndex++;
1069
1070 //
1071 // Skip ';' characters in Supported
1072 //
1073 for ( ; *Supported != '\0' && *Supported == ';'; Supported++) {
1074 }
1075 }
1076 }
1077}
1078
1118CHAR8 *
1119EFIAPI
1121 IN CONST CHAR8 *SupportedLanguages,
1122 IN UINTN Iso639Language,
1123 ...
1124 )
1125{
1126 VA_LIST Args;
1127 CHAR8 *Language;
1128 UINTN CompareLength;
1129 UINTN LanguageLength;
1130 CONST CHAR8 *Supported;
1131 CHAR8 *Buffer;
1132
1133 if (SupportedLanguages == NULL) {
1134 return NULL;
1135 }
1136
1137 VA_START (Args, Iso639Language);
1138 while ((Language = VA_ARG (Args, CHAR8 *)) != NULL) {
1139 //
1140 // Default to ISO 639-2 mode
1141 //
1142 CompareLength = 3;
1143 LanguageLength = MIN (3, AsciiStrLen (Language));
1144
1145 //
1146 // If in RFC 4646 mode, then determine the length of the first RFC 4646 language code in Language
1147 //
1148 if (Iso639Language == 0) {
1149 for (LanguageLength = 0; Language[LanguageLength] != 0 && Language[LanguageLength] != ';'; LanguageLength++) {
1150 }
1151 }
1152
1153 //
1154 // Trim back the length of Language used until it is empty
1155 //
1156 while (LanguageLength > 0) {
1157 //
1158 // Loop through all language codes in SupportedLanguages
1159 //
1160 for (Supported = SupportedLanguages; *Supported != '\0'; Supported += CompareLength) {
1161 //
1162 // In RFC 4646 mode, then Loop through all language codes in SupportedLanguages
1163 //
1164 if (Iso639Language == 0) {
1165 //
1166 // Skip ';' characters in Supported
1167 //
1168 for ( ; *Supported != '\0' && *Supported == ';'; Supported++) {
1169 }
1170
1171 //
1172 // Determine the length of the next language code in Supported
1173 //
1174 for (CompareLength = 0; Supported[CompareLength] != 0 && Supported[CompareLength] != ';'; CompareLength++) {
1175 }
1176
1177 //
1178 // If Language is longer than the Supported, then skip to the next language
1179 //
1180 if (LanguageLength > CompareLength) {
1181 continue;
1182 }
1183 }
1184
1185 //
1186 // See if the first LanguageLength characters in Supported match Language
1187 //
1188 if (AsciiStrnCmp (Supported, Language, LanguageLength) == 0) {
1189 VA_END (Args);
1190
1192 Buffer[CompareLength] = '\0';
1193 return CopyMem (Buffer, Supported, CompareLength);
1194 }
1195 }
1196
1197 if (Iso639Language != 0) {
1198 //
1199 // If ISO 639 mode, then each language can only be tested once
1200 //
1201 LanguageLength = 0;
1202 } else {
1203 //
1204 // If RFC 4646 mode, then trim Language from the right to the next '-' character
1205 //
1206 for (LanguageLength--; LanguageLength > 0 && Language[LanguageLength] != '-'; LanguageLength--) {
1207 }
1208 }
1209 }
1210 }
1211
1212 VA_END (Args);
1213
1214 //
1215 // No matches were found
1216 //
1217 return NULL;
1218}
1219
1240BOOLEAN
1241EFIAPI
1243 IN UINT32 Attributes,
1244 IN VA_LIST Marker
1245 )
1246{
1247 EFI_STATUS Status;
1248 VA_LIST Args;
1249 VARIABLE_ENTRY_CONSISTENCY *VariableEntry;
1250 UINT64 MaximumVariableStorageSize;
1251 UINT64 RemainingVariableStorageSize;
1252 UINT64 MaximumVariableSize;
1253 UINTN TotalNeededSize;
1254 UINTN OriginalVarSize;
1255 VARIABLE_STORE_HEADER *VariableStoreHeader;
1256 VARIABLE_POINTER_TRACK VariablePtrTrack;
1257 VARIABLE_HEADER *NextVariable;
1258 UINTN VarNameSize;
1259 UINTN VarDataSize;
1260
1261 //
1262 // Non-Volatile related.
1263 //
1264 VariableStoreHeader = mNvVariableCache;
1265
1267 Attributes,
1268 &MaximumVariableStorageSize,
1269 &RemainingVariableStorageSize,
1270 &MaximumVariableSize
1271 );
1272 ASSERT_EFI_ERROR (Status);
1273
1274 TotalNeededSize = 0;
1275 VA_COPY (Args, Marker);
1276 VariableEntry = VA_ARG (Args, VARIABLE_ENTRY_CONSISTENCY *);
1277 while (VariableEntry != NULL) {
1278 //
1279 // Calculate variable total size.
1280 //
1281 VarNameSize = StrSize (VariableEntry->Name);
1282 VarNameSize += GET_PAD_SIZE (VarNameSize);
1283 VarDataSize = VariableEntry->VariableSize;
1284 VarDataSize += GET_PAD_SIZE (VarDataSize);
1285 VariableEntry->VariableSize = HEADER_ALIGN (
1288 ) + VarNameSize + VarDataSize
1289 );
1290
1291 TotalNeededSize += VariableEntry->VariableSize;
1292 VariableEntry = VA_ARG (Args, VARIABLE_ENTRY_CONSISTENCY *);
1293 }
1294
1295 VA_END (Args);
1296
1297 if (RemainingVariableStorageSize >= TotalNeededSize) {
1298 //
1299 // Already have enough space.
1300 //
1301 return TRUE;
1302 } else if (AtRuntime ()) {
1303 //
1304 // At runtime, no reclaim.
1305 // The original variable space of Variables can't be reused.
1306 //
1307 return FALSE;
1308 }
1309
1310 VA_COPY (Args, Marker);
1311 VariableEntry = VA_ARG (Args, VARIABLE_ENTRY_CONSISTENCY *);
1312 while (VariableEntry != NULL) {
1313 //
1314 // Check if Variable[Index] has been present and get its size.
1315 //
1316 OriginalVarSize = 0;
1317 VariablePtrTrack.StartPtr = GetStartPointer (VariableStoreHeader);
1318 VariablePtrTrack.EndPtr = GetEndPointer (VariableStoreHeader);
1319 Status = FindVariableEx (
1320 VariableEntry->Name,
1321 VariableEntry->Guid,
1322 FALSE,
1323 &VariablePtrTrack,
1325 );
1326 if (!EFI_ERROR (Status)) {
1327 //
1328 // Get size of Variable[Index].
1329 //
1330 NextVariable = GetNextVariablePtr (VariablePtrTrack.CurrPtr, mVariableModuleGlobal->VariableGlobal.AuthFormat);
1331 OriginalVarSize = (UINTN)NextVariable - (UINTN)VariablePtrTrack.CurrPtr;
1332 //
1333 // Add the original size of Variable[Index] to remaining variable storage size.
1334 //
1335 RemainingVariableStorageSize += OriginalVarSize;
1336 }
1337
1338 if (VariableEntry->VariableSize > RemainingVariableStorageSize) {
1339 //
1340 // No enough space for Variable[Index].
1341 //
1342 VA_END (Args);
1343 return FALSE;
1344 }
1345
1346 //
1347 // Sub the (new) size of Variable[Index] from remaining variable storage size.
1348 //
1349 RemainingVariableStorageSize -= VariableEntry->VariableSize;
1350 VariableEntry = VA_ARG (Args, VARIABLE_ENTRY_CONSISTENCY *);
1351 }
1352
1353 VA_END (Args);
1354
1355 return TRUE;
1356}
1357
1377BOOLEAN
1378EFIAPI
1380 IN UINT32 Attributes,
1381 ...
1382 )
1383{
1384 VA_LIST Marker;
1385 BOOLEAN Return;
1386
1387 VA_START (Marker, Attributes);
1388
1389 Return = CheckRemainingSpaceForConsistencyInternal (Attributes, Marker);
1390
1391 VA_END (Marker);
1392
1393 return Return;
1394}
1395
1416EFI_STATUS
1418 IN CHAR16 *VariableName,
1419 IN VOID *Data,
1420 IN UINTN DataSize
1421 )
1422{
1423 EFI_STATUS Status;
1424 CHAR8 *BestPlatformLang;
1425 CHAR8 *BestLang;
1426 UINTN Index;
1427 UINT32 Attributes;
1428 VARIABLE_POINTER_TRACK Variable;
1429 BOOLEAN SetLanguageCodes;
1430 VARIABLE_ENTRY_CONSISTENCY VariableEntry[2];
1431
1432 //
1433 // Don't do updates for delete operation
1434 //
1435 if (DataSize == 0) {
1436 return EFI_SUCCESS;
1437 }
1438
1439 SetLanguageCodes = FALSE;
1440
1441 if (StrCmp (VariableName, EFI_PLATFORM_LANG_CODES_VARIABLE_NAME) == 0) {
1442 //
1443 // PlatformLangCodes is a volatile variable, so it can not be updated at runtime.
1444 //
1445 if (AtRuntime ()) {
1446 return EFI_WRITE_PROTECTED;
1447 }
1448
1449 SetLanguageCodes = TRUE;
1450
1451 //
1452 // According to UEFI spec, PlatformLangCodes is only set once in firmware initialization, and is read-only
1453 // Therefore, in variable driver, only store the original value for other use.
1454 //
1457 }
1458
1459 mVariableModuleGlobal->PlatformLangCodes = AllocateRuntimeCopyPool (DataSize, Data);
1461
1462 //
1463 // PlatformLang holds a single language from PlatformLangCodes,
1464 // so the size of PlatformLangCodes is enough for the PlatformLang.
1465 //
1466 if (mVariableModuleGlobal->PlatformLang != NULL) {
1468 }
1469
1470 mVariableModuleGlobal->PlatformLang = AllocateRuntimePool (DataSize);
1472 } else if (StrCmp (VariableName, EFI_LANG_CODES_VARIABLE_NAME) == 0) {
1473 //
1474 // LangCodes is a volatile variable, so it can not be updated at runtime.
1475 //
1476 if (AtRuntime ()) {
1477 return EFI_WRITE_PROTECTED;
1478 }
1479
1480 SetLanguageCodes = TRUE;
1481
1482 //
1483 // According to UEFI spec, LangCodes is only set once in firmware initialization, and is read-only
1484 // Therefore, in variable driver, only store the original value for other use.
1485 //
1486 if (mVariableModuleGlobal->LangCodes != NULL) {
1487 FreePool (mVariableModuleGlobal->LangCodes);
1488 }
1489
1490 mVariableModuleGlobal->LangCodes = AllocateRuntimeCopyPool (DataSize, Data);
1492 }
1493
1494 if ( SetLanguageCodes
1496 && (mVariableModuleGlobal->LangCodes != NULL))
1497 {
1498 //
1499 // Update Lang if PlatformLang is already set
1500 // Update PlatformLang if Lang is already set
1501 //
1502 Status = FindVariable (EFI_PLATFORM_LANG_VARIABLE_NAME, &gEfiGlobalVariableGuid, &Variable, &mVariableModuleGlobal->VariableGlobal, FALSE);
1503 if (!EFI_ERROR (Status)) {
1504 //
1505 // Update Lang
1506 //
1507 VariableName = EFI_PLATFORM_LANG_VARIABLE_NAME;
1510 } else {
1511 Status = FindVariable (EFI_LANG_VARIABLE_NAME, &gEfiGlobalVariableGuid, &Variable, &mVariableModuleGlobal->VariableGlobal, FALSE);
1512 if (!EFI_ERROR (Status)) {
1513 //
1514 // Update PlatformLang
1515 //
1516 VariableName = EFI_LANG_VARIABLE_NAME;
1519 } else {
1520 //
1521 // Neither PlatformLang nor Lang is set, directly return
1522 //
1523 return EFI_SUCCESS;
1524 }
1525 }
1526 }
1527
1528 Status = EFI_SUCCESS;
1529
1530 //
1531 // According to UEFI spec, "Lang" and "PlatformLang" is NV|BS|RT attributions.
1532 //
1533 Attributes = EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS;
1534
1535 if (StrCmp (VariableName, EFI_PLATFORM_LANG_VARIABLE_NAME) == 0) {
1536 //
1537 // Update Lang when PlatformLangCodes/LangCodes were set.
1538 //
1540 //
1541 // When setting PlatformLang, firstly get most matched language string from supported language codes.
1542 //
1543 BestPlatformLang = VariableGetBestLanguage (mVariableModuleGlobal->PlatformLangCodes, FALSE, Data, NULL);
1544 if (BestPlatformLang != NULL) {
1545 //
1546 // Get the corresponding index in language codes.
1547 //
1549
1550 //
1551 // Get the corresponding ISO639 language tag according to RFC4646 language tag.
1552 //
1554
1555 //
1556 // Check the variable space for both Lang and PlatformLang variable.
1557 //
1558 VariableEntry[0].VariableSize = ISO_639_2_ENTRY_SIZE + 1;
1559 VariableEntry[0].Guid = &gEfiGlobalVariableGuid;
1560 VariableEntry[0].Name = EFI_LANG_VARIABLE_NAME;
1561
1562 VariableEntry[1].VariableSize = AsciiStrSize (BestPlatformLang);
1563 VariableEntry[1].Guid = &gEfiGlobalVariableGuid;
1564 VariableEntry[1].Name = EFI_PLATFORM_LANG_VARIABLE_NAME;
1565 if (!CheckRemainingSpaceForConsistency (VARIABLE_ATTRIBUTE_NV_BS_RT, &VariableEntry[0], &VariableEntry[1], NULL)) {
1566 //
1567 // No enough variable space to set both Lang and PlatformLang successfully.
1568 //
1569 Status = EFI_OUT_OF_RESOURCES;
1570 } else {
1571 //
1572 // Successfully convert PlatformLang to Lang, and set the BestLang value into Lang variable simultaneously.
1573 //
1574 FindVariable (EFI_LANG_VARIABLE_NAME, &gEfiGlobalVariableGuid, &Variable, &mVariableModuleGlobal->VariableGlobal, FALSE);
1575
1576 Status = UpdateVariable (
1577 EFI_LANG_VARIABLE_NAME,
1579 BestLang,
1581 Attributes,
1582 0,
1583 0,
1584 &Variable,
1585 NULL
1586 );
1587 }
1588
1589 DEBUG ((DEBUG_INFO, "Variable Driver Auto Update PlatformLang, PlatformLang:%a, Lang:%a Status: %r\n", BestPlatformLang, BestLang, Status));
1590 }
1591 }
1592 } else if (StrCmp (VariableName, EFI_LANG_VARIABLE_NAME) == 0) {
1593 //
1594 // Update PlatformLang when PlatformLangCodes/LangCodes were set.
1595 //
1597 //
1598 // When setting Lang, firstly get most matched language string from supported language codes.
1599 //
1600 BestLang = VariableGetBestLanguage (mVariableModuleGlobal->LangCodes, TRUE, Data, NULL);
1601 if (BestLang != NULL) {
1602 //
1603 // Get the corresponding index in language codes.
1604 //
1606
1607 //
1608 // Get the corresponding RFC4646 language tag according to ISO639 language tag.
1609 //
1610 BestPlatformLang = GetLangFromSupportedLangCodes (mVariableModuleGlobal->PlatformLangCodes, Index, FALSE);
1611
1612 //
1613 // Check the variable space for both PlatformLang and Lang variable.
1614 //
1615 VariableEntry[0].VariableSize = AsciiStrSize (BestPlatformLang);
1616 VariableEntry[0].Guid = &gEfiGlobalVariableGuid;
1617 VariableEntry[0].Name = EFI_PLATFORM_LANG_VARIABLE_NAME;
1618
1619 VariableEntry[1].VariableSize = ISO_639_2_ENTRY_SIZE + 1;
1620 VariableEntry[1].Guid = &gEfiGlobalVariableGuid;
1621 VariableEntry[1].Name = EFI_LANG_VARIABLE_NAME;
1622 if (!CheckRemainingSpaceForConsistency (VARIABLE_ATTRIBUTE_NV_BS_RT, &VariableEntry[0], &VariableEntry[1], NULL)) {
1623 //
1624 // No enough variable space to set both PlatformLang and Lang successfully.
1625 //
1626 Status = EFI_OUT_OF_RESOURCES;
1627 } else {
1628 //
1629 // Successfully convert Lang to PlatformLang, and set the BestPlatformLang value into PlatformLang variable simultaneously.
1630 //
1631 FindVariable (EFI_PLATFORM_LANG_VARIABLE_NAME, &gEfiGlobalVariableGuid, &Variable, &mVariableModuleGlobal->VariableGlobal, FALSE);
1632
1633 Status = UpdateVariable (
1634 EFI_PLATFORM_LANG_VARIABLE_NAME,
1636 BestPlatformLang,
1637 AsciiStrSize (BestPlatformLang),
1638 Attributes,
1639 0,
1640 0,
1641 &Variable,
1642 NULL
1643 );
1644 }
1645
1646 DEBUG ((DEBUG_INFO, "Variable Driver Auto Update Lang, Lang:%a, PlatformLang:%a Status: %r\n", BestLang, BestPlatformLang, Status));
1647 }
1648 }
1649 }
1650
1651 if (SetLanguageCodes) {
1652 //
1653 // Continue to set PlatformLangCodes or LangCodes.
1654 //
1655 return EFI_SUCCESS;
1656 } else {
1657 return Status;
1658 }
1659}
1660
1679EFI_STATUS
1681 IN CHAR16 *VariableName,
1682 IN EFI_GUID *VendorGuid,
1683 IN VOID *Data,
1684 IN UINTN DataSize,
1685 IN UINT32 Attributes OPTIONAL,
1686 IN UINT32 KeyIndex OPTIONAL,
1687 IN UINT64 MonotonicCount OPTIONAL,
1688 IN OUT VARIABLE_POINTER_TRACK *CacheVariable,
1689 IN EFI_TIME *TimeStamp OPTIONAL
1690 )
1691{
1692 EFI_STATUS Status;
1693 VARIABLE_HEADER *NextVariable;
1694 UINTN ScratchSize;
1695 UINTN MaxDataSize;
1696 UINTN VarNameOffset;
1697 UINTN VarDataOffset;
1698 UINTN VarNameSize;
1699 UINTN VarSize;
1700 BOOLEAN Volatile;
1701 EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *Fvb;
1702 UINT8 State;
1703 VARIABLE_POINTER_TRACK *Variable;
1704 VARIABLE_POINTER_TRACK NvVariable;
1705 VARIABLE_STORE_HEADER *VariableStoreHeader;
1706 VARIABLE_RUNTIME_CACHE *VolatileCacheInstance;
1707 UINT8 *BufferForMerge;
1708 UINTN MergedBufSize;
1709 BOOLEAN DataReady;
1710 UINTN DataOffset;
1711 BOOLEAN IsCommonVariable;
1712 BOOLEAN IsCommonUserVariable;
1713 AUTHENTICATED_VARIABLE_HEADER *AuthVariable;
1714 BOOLEAN AuthFormat;
1715
1717 //
1718 // The FVB protocol is not ready, so the EFI_VARIABLE_WRITE_ARCH_PROTOCOL is not installed.
1719 //
1720 if ((Attributes & EFI_VARIABLE_NON_VOLATILE) != 0) {
1721 //
1722 // Trying to update NV variable prior to the installation of EFI_VARIABLE_WRITE_ARCH_PROTOCOL
1723 //
1724 DEBUG ((DEBUG_ERROR, "Update NV variable before EFI_VARIABLE_WRITE_ARCH_PROTOCOL ready - %r\n", EFI_NOT_AVAILABLE_YET));
1725 return EFI_NOT_AVAILABLE_YET;
1726 } else if ((Attributes & VARIABLE_ATTRIBUTE_AT_AW) != 0) {
1727 //
1728 // Trying to update volatile authenticated variable prior to the installation of EFI_VARIABLE_WRITE_ARCH_PROTOCOL
1729 // The authenticated variable perhaps is not initialized, just return here.
1730 //
1731 DEBUG ((DEBUG_ERROR, "Update AUTH variable before EFI_VARIABLE_WRITE_ARCH_PROTOCOL ready - %r\n", EFI_NOT_AVAILABLE_YET));
1732 return EFI_NOT_AVAILABLE_YET;
1733 }
1734 }
1735
1737
1738 //
1739 // Check if CacheVariable points to the variable in variable HOB.
1740 // If yes, let CacheVariable points to the variable in NV variable cache.
1741 //
1742 if ((CacheVariable->CurrPtr != NULL) &&
1744 (CacheVariable->StartPtr == GetStartPointer ((VARIABLE_STORE_HEADER *)(UINTN)mVariableModuleGlobal->VariableGlobal.HobVariableBase))
1745 )
1746 {
1747 CacheVariable->StartPtr = GetStartPointer (mNvVariableCache);
1748 CacheVariable->EndPtr = GetEndPointer (mNvVariableCache);
1749 CacheVariable->Volatile = FALSE;
1750 Status = FindVariableEx (VariableName, VendorGuid, FALSE, CacheVariable, AuthFormat);
1751 if ((CacheVariable->CurrPtr == NULL) || EFI_ERROR (Status)) {
1752 //
1753 // There is no matched variable in NV variable cache.
1754 //
1755 if ((((Attributes & EFI_VARIABLE_APPEND_WRITE) == 0) && (DataSize == 0)) || (Attributes == 0)) {
1756 //
1757 // It is to delete variable,
1758 // go to delete this variable in variable HOB and
1759 // try to flush other variables from HOB to flash.
1760 //
1761 UpdateVariableInfo (VariableName, VendorGuid, FALSE, FALSE, FALSE, TRUE, FALSE, &gVariableInfo);
1762 FlushHobVariableToFlash (VariableName, VendorGuid);
1763 return EFI_SUCCESS;
1764 }
1765 }
1766 }
1767
1768 if ((CacheVariable->CurrPtr == NULL) || CacheVariable->Volatile) {
1769 Variable = CacheVariable;
1770 } else {
1771 //
1772 // Update/Delete existing NV variable.
1773 // CacheVariable points to the variable in the memory copy of Flash area
1774 // Now let Variable points to the same variable in Flash area.
1775 //
1776 VariableStoreHeader = (VARIABLE_STORE_HEADER *)((UINTN)mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase);
1777 Variable = &NvVariable;
1778 Variable->StartPtr = GetStartPointer (VariableStoreHeader);
1779 Variable->EndPtr = (VARIABLE_HEADER *)((UINTN)Variable->StartPtr + ((UINTN)CacheVariable->EndPtr - (UINTN)CacheVariable->StartPtr));
1780
1781 Variable->CurrPtr = (VARIABLE_HEADER *)((UINTN)Variable->StartPtr + ((UINTN)CacheVariable->CurrPtr - (UINTN)CacheVariable->StartPtr));
1782 if (CacheVariable->InDeletedTransitionPtr != NULL) {
1783 Variable->InDeletedTransitionPtr = (VARIABLE_HEADER *)((UINTN)Variable->StartPtr + ((UINTN)CacheVariable->InDeletedTransitionPtr - (UINTN)CacheVariable->StartPtr));
1784 } else {
1785 Variable->InDeletedTransitionPtr = NULL;
1786 }
1787
1788 Variable->Volatile = FALSE;
1789 }
1790
1792
1793 //
1794 // Tricky part: Use scratch data area at the end of volatile variable store
1795 // as a temporary storage.
1796 //
1797 NextVariable = GetEndPointer ((VARIABLE_STORE_HEADER *)((UINTN)mVariableModuleGlobal->VariableGlobal.VolatileVariableBase));
1799 SetMem (NextVariable, ScratchSize, 0xff);
1800 DataReady = FALSE;
1801
1802 if (Variable->CurrPtr != NULL) {
1803 //
1804 // Update/Delete existing variable.
1805 //
1806 if (AtRuntime ()) {
1807 //
1808 // If AtRuntime and the variable is Volatile and Runtime Access,
1809 // the volatile is ReadOnly, and SetVariable should be aborted and
1810 // return EFI_WRITE_PROTECTED.
1811 //
1812 if (Variable->Volatile) {
1813 Status = EFI_WRITE_PROTECTED;
1814 goto Done;
1815 }
1816
1817 //
1818 // Only variable that have NV attributes can be updated/deleted in Runtime.
1819 //
1820 if ((CacheVariable->CurrPtr->Attributes & EFI_VARIABLE_NON_VOLATILE) == 0) {
1821 Status = EFI_INVALID_PARAMETER;
1822 goto Done;
1823 }
1824
1825 //
1826 // Only variable that have RT attributes can be updated/deleted in Runtime.
1827 //
1828 if ((CacheVariable->CurrPtr->Attributes & EFI_VARIABLE_RUNTIME_ACCESS) == 0) {
1829 Status = EFI_INVALID_PARAMETER;
1830 goto Done;
1831 }
1832 }
1833
1834 //
1835 // Setting a data variable with no access, or zero DataSize attributes
1836 // causes it to be deleted.
1837 // When the EFI_VARIABLE_APPEND_WRITE attribute is set, DataSize of zero will
1838 // not delete the variable.
1839 //
1840 if ((((Attributes & EFI_VARIABLE_APPEND_WRITE) == 0) && (DataSize == 0)) || ((Attributes & (EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS)) == 0)) {
1841 if (Variable->InDeletedTransitionPtr != NULL) {
1842 //
1843 // Both ADDED and IN_DELETED_TRANSITION variable are present,
1844 // set IN_DELETED_TRANSITION one to DELETED state first.
1845 //
1846 ASSERT (CacheVariable->InDeletedTransitionPtr != NULL);
1847 State = CacheVariable->InDeletedTransitionPtr->State;
1848 State &= VAR_DELETED;
1849 Status = UpdateVariableStore (
1851 Variable->Volatile,
1852 FALSE,
1853 Fvb,
1854 (UINTN)&Variable->InDeletedTransitionPtr->State,
1855 sizeof (UINT8),
1856 &State
1857 );
1858 if (!EFI_ERROR (Status)) {
1859 if (!Variable->Volatile) {
1860 CacheVariable->InDeletedTransitionPtr->State = State;
1861 }
1862 } else {
1863 goto Done;
1864 }
1865 }
1866
1867 State = CacheVariable->CurrPtr->State;
1868 State &= VAR_DELETED;
1869
1870 Status = UpdateVariableStore (
1872 Variable->Volatile,
1873 FALSE,
1874 Fvb,
1875 (UINTN)&Variable->CurrPtr->State,
1876 sizeof (UINT8),
1877 &State
1878 );
1879 if (!EFI_ERROR (Status)) {
1880 UpdateVariableInfo (VariableName, VendorGuid, Variable->Volatile, FALSE, FALSE, TRUE, FALSE, &gVariableInfo);
1881 if (!Variable->Volatile) {
1882 CacheVariable->CurrPtr->State = State;
1883 FlushHobVariableToFlash (VariableName, VendorGuid);
1884 }
1885 }
1886
1887 goto Done;
1888 }
1889
1890 //
1891 // If the variable is marked valid, and the same data has been passed in,
1892 // then return to the caller immediately.
1893 //
1894 if ((DataSizeOfVariable (CacheVariable->CurrPtr, AuthFormat) == DataSize) &&
1895 (CompareMem (Data, GetVariableDataPtr (CacheVariable->CurrPtr, AuthFormat), DataSize) == 0) &&
1896 ((Attributes & EFI_VARIABLE_APPEND_WRITE) == 0) &&
1897 (TimeStamp == NULL))
1898 {
1899 //
1900 // Variable content unchanged and no need to update timestamp, just return.
1901 //
1902 UpdateVariableInfo (VariableName, VendorGuid, Variable->Volatile, FALSE, TRUE, FALSE, FALSE, &gVariableInfo);
1903 Status = EFI_SUCCESS;
1904 goto Done;
1905 } else if ((CacheVariable->CurrPtr->State == VAR_ADDED) ||
1906 (CacheVariable->CurrPtr->State == (VAR_ADDED & VAR_IN_DELETED_TRANSITION)))
1907 {
1908 //
1909 // EFI_VARIABLE_APPEND_WRITE attribute only effects for existing variable.
1910 //
1911 if ((Attributes & EFI_VARIABLE_APPEND_WRITE) != 0) {
1912 //
1913 // NOTE: From 0 to DataOffset of NextVariable is reserved for Variable Header and Name.
1914 // From DataOffset of NextVariable is to save the existing variable data.
1915 //
1916 DataOffset = GetVariableDataOffset (CacheVariable->CurrPtr, AuthFormat);
1917 BufferForMerge = (UINT8 *)((UINTN)NextVariable + DataOffset);
1918 CopyMem (
1919 BufferForMerge,
1920 (UINT8 *)((UINTN)CacheVariable->CurrPtr + DataOffset),
1921 DataSizeOfVariable (CacheVariable->CurrPtr, AuthFormat)
1922 );
1923
1924 //
1925 // Set Max Auth/Non-Volatile/Volatile Variable Data Size as default MaxDataSize.
1926 //
1927 if ((Attributes & VARIABLE_ATTRIBUTE_AT_AW) != 0) {
1928 MaxDataSize = mVariableModuleGlobal->MaxAuthVariableSize - DataOffset;
1929 } else if ((Attributes & EFI_VARIABLE_NON_VOLATILE) != 0) {
1930 MaxDataSize = mVariableModuleGlobal->MaxVariableSize - DataOffset;
1931 } else {
1932 MaxDataSize = mVariableModuleGlobal->MaxVolatileVariableSize - DataOffset;
1933 }
1934
1935 //
1936 // Append the new data to the end of existing data.
1937 // Max Harware error record variable data size is different from common/auth variable.
1938 //
1939 if ((Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == EFI_VARIABLE_HARDWARE_ERROR_RECORD) {
1940 MaxDataSize = PcdGet32 (PcdMaxHardwareErrorVariableSize) - DataOffset;
1941 }
1942
1943 if (DataSizeOfVariable (CacheVariable->CurrPtr, AuthFormat) + DataSize > MaxDataSize) {
1944 //
1945 // Existing data size + new data size exceed maximum variable size limitation.
1946 //
1947 Status = EFI_INVALID_PARAMETER;
1948 goto Done;
1949 }
1950
1951 CopyMem (
1952 (UINT8 *)(
1953 (UINTN)BufferForMerge + DataSizeOfVariable (CacheVariable->CurrPtr, AuthFormat)
1954 ),
1955 Data,
1956 DataSize
1957 );
1958 MergedBufSize = DataSizeOfVariable (CacheVariable->CurrPtr, AuthFormat) +
1959 DataSize;
1960
1961 //
1962 // BufferForMerge(from DataOffset of NextVariable) has included the merged existing and new data.
1963 //
1964 Data = BufferForMerge;
1965 DataSize = MergedBufSize;
1966 DataReady = TRUE;
1967 }
1968
1969 //
1970 // Mark the old variable as in delete transition.
1971 //
1972 State = CacheVariable->CurrPtr->State;
1973 State &= VAR_IN_DELETED_TRANSITION;
1974
1975 Status = UpdateVariableStore (
1977 Variable->Volatile,
1978 FALSE,
1979 Fvb,
1980 (UINTN)&Variable->CurrPtr->State,
1981 sizeof (UINT8),
1982 &State
1983 );
1984 if (EFI_ERROR (Status)) {
1985 goto Done;
1986 }
1987
1988 if (!Variable->Volatile) {
1989 CacheVariable->CurrPtr->State = State;
1990 }
1991 }
1992 } else {
1993 //
1994 // Not found existing variable. Create a new variable.
1995 //
1996
1997 if ((DataSize == 0) && ((Attributes & EFI_VARIABLE_APPEND_WRITE) != 0)) {
1998 Status = EFI_SUCCESS;
1999 goto Done;
2000 }
2001
2002 //
2003 // Make sure we are trying to create a new variable.
2004 // Setting a data variable with zero DataSize or no access attributes means to delete it.
2005 //
2006 if ((DataSize == 0) || ((Attributes & (EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS)) == 0)) {
2007 Status = EFI_NOT_FOUND;
2008 goto Done;
2009 }
2010
2011 //
2012 // Only variable have NV|RT attribute can be created in Runtime.
2013 //
2014 if (AtRuntime () &&
2015 (((Attributes & EFI_VARIABLE_RUNTIME_ACCESS) == 0) || ((Attributes & EFI_VARIABLE_NON_VOLATILE) == 0)))
2016 {
2017 Status = EFI_INVALID_PARAMETER;
2018 goto Done;
2019 }
2020 }
2021
2022 //
2023 // Function part - create a new variable and copy the data.
2024 // Both update a variable and create a variable will come here.
2025 //
2026 NextVariable->StartId = VARIABLE_DATA;
2027 //
2028 // NextVariable->State = VAR_ADDED;
2029 //
2030 NextVariable->Reserved = 0;
2032 AuthVariable = (AUTHENTICATED_VARIABLE_HEADER *)NextVariable;
2033 AuthVariable->PubKeyIndex = KeyIndex;
2034 AuthVariable->MonotonicCount = MonotonicCount;
2035 ZeroMem (&AuthVariable->TimeStamp, sizeof (EFI_TIME));
2036
2037 if (((Attributes & EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS) != 0) &&
2038 (TimeStamp != NULL))
2039 {
2040 if ((Attributes & EFI_VARIABLE_APPEND_WRITE) == 0) {
2041 CopyMem (&AuthVariable->TimeStamp, TimeStamp, sizeof (EFI_TIME));
2042 } else {
2043 //
2044 // In the case when the EFI_VARIABLE_APPEND_WRITE attribute is set, only
2045 // when the new TimeStamp value is later than the current timestamp associated
2046 // with the variable, we need associate the new timestamp with the updated value.
2047 //
2048 if (Variable->CurrPtr != NULL) {
2049 if (VariableCompareTimeStampInternal (&(((AUTHENTICATED_VARIABLE_HEADER *)CacheVariable->CurrPtr)->TimeStamp), TimeStamp)) {
2050 CopyMem (&AuthVariable->TimeStamp, TimeStamp, sizeof (EFI_TIME));
2051 } else {
2052 CopyMem (&AuthVariable->TimeStamp, &(((AUTHENTICATED_VARIABLE_HEADER *)CacheVariable->CurrPtr)->TimeStamp), sizeof (EFI_TIME));
2053 }
2054 }
2055 }
2056 }
2057 }
2058
2059 //
2060 // The EFI_VARIABLE_APPEND_WRITE attribute will never be set in the returned
2061 // Attributes bitmask parameter of a GetVariable() call.
2062 //
2063 NextVariable->Attributes = Attributes & (~EFI_VARIABLE_APPEND_WRITE);
2064
2065 VarNameOffset = GetVariableHeaderSize (AuthFormat);
2066 VarNameSize = StrSize (VariableName);
2067 CopyMem (
2068 (UINT8 *)((UINTN)NextVariable + VarNameOffset),
2069 VariableName,
2070 VarNameSize
2071 );
2072 VarDataOffset = VarNameOffset + VarNameSize + GET_PAD_SIZE (VarNameSize);
2073
2074 //
2075 // If DataReady is TRUE, it means the variable data has been saved into
2076 // NextVariable during EFI_VARIABLE_APPEND_WRITE operation preparation.
2077 //
2078 if (!DataReady) {
2079 CopyMem (
2080 (UINT8 *)((UINTN)NextVariable + VarDataOffset),
2081 Data,
2082 DataSize
2083 );
2084 }
2085
2086 CopyMem (
2087 GetVendorGuidPtr (NextVariable, AuthFormat),
2088 VendorGuid,
2089 sizeof (EFI_GUID)
2090 );
2091 //
2092 // There will be pad bytes after Data, the NextVariable->NameSize and
2093 // NextVariable->DataSize should not include pad size so that variable
2094 // service can get actual size in GetVariable.
2095 //
2096 SetNameSizeOfVariable (NextVariable, VarNameSize, AuthFormat);
2097 SetDataSizeOfVariable (NextVariable, DataSize, AuthFormat);
2098
2099 //
2100 // The actual size of the variable that stores in storage should
2101 // include pad size.
2102 //
2103 VarSize = VarDataOffset + DataSize + GET_PAD_SIZE (DataSize);
2104 if ((Attributes & EFI_VARIABLE_NON_VOLATILE) != 0) {
2105 //
2106 // Create a nonvolatile variable.
2107 //
2108 Volatile = FALSE;
2109
2110 IsCommonVariable = FALSE;
2111 IsCommonUserVariable = FALSE;
2112 if ((Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == 0) {
2113 IsCommonVariable = TRUE;
2114 IsCommonUserVariable = IsUserVariable (NextVariable);
2115 }
2116
2117 if ( ( ((Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) != 0)
2118 && ((VarSize + mVariableModuleGlobal->HwErrVariableTotalSize) > PcdGet32 (PcdHwErrStorageSize)))
2122 {
2123 if (AtRuntime ()) {
2125 RecordVarErrorFlag (VAR_ERROR_FLAG_USER_ERROR, VariableName, VendorGuid, Attributes, VarSize);
2126 }
2127
2129 RecordVarErrorFlag (VAR_ERROR_FLAG_SYSTEM_ERROR, VariableName, VendorGuid, Attributes, VarSize);
2130 }
2131
2132 Status = EFI_OUT_OF_RESOURCES;
2133 goto Done;
2134 }
2135
2136 //
2137 // Perform garbage collection & reclaim operation, and integrate the new variable at the same time.
2138 //
2139 Status = Reclaim (
2142 FALSE,
2143 Variable,
2144 NextVariable,
2145 HEADER_ALIGN (VarSize)
2146 );
2147 if (!EFI_ERROR (Status)) {
2148 //
2149 // The new variable has been integrated successfully during reclaiming.
2150 //
2151 if (Variable->CurrPtr != NULL) {
2152 CacheVariable->CurrPtr = (VARIABLE_HEADER *)((UINTN)CacheVariable->StartPtr + ((UINTN)Variable->CurrPtr - (UINTN)Variable->StartPtr));
2153 CacheVariable->InDeletedTransitionPtr = NULL;
2154 }
2155
2156 UpdateVariableInfo (VariableName, VendorGuid, FALSE, FALSE, TRUE, FALSE, FALSE, &gVariableInfo);
2157 FlushHobVariableToFlash (VariableName, VendorGuid);
2158 } else {
2160 RecordVarErrorFlag (VAR_ERROR_FLAG_USER_ERROR, VariableName, VendorGuid, Attributes, VarSize);
2161 }
2162
2164 RecordVarErrorFlag (VAR_ERROR_FLAG_SYSTEM_ERROR, VariableName, VendorGuid, Attributes, VarSize);
2165 }
2166 }
2167
2168 goto Done;
2169 }
2170
2172 //
2173 // Four steps
2174 // 1. Write variable header
2175 // 2. Set variable state to header valid
2176 // 3. Write variable data
2177 // 4. Set variable state to valid
2178 //
2179 //
2180 // Step 1:
2181 //
2182 Status = UpdateVariableStore (
2184 FALSE,
2185 TRUE,
2186 Fvb,
2188 (UINT32)GetVariableHeaderSize (AuthFormat),
2189 (UINT8 *)NextVariable
2190 );
2191
2192 if (EFI_ERROR (Status)) {
2193 goto Done;
2194 }
2195
2196 //
2197 // Step 2:
2198 //
2199 NextVariable->State = VAR_HEADER_VALID_ONLY;
2200 Status = UpdateVariableStore (
2202 FALSE,
2203 TRUE,
2204 Fvb,
2205 mVariableModuleGlobal->NonVolatileLastVariableOffset + OFFSET_OF (VARIABLE_HEADER, State),
2206 sizeof (UINT8),
2207 &NextVariable->State
2208 );
2209
2210 if (EFI_ERROR (Status)) {
2211 goto Done;
2212 }
2213
2214 //
2215 // Step 3:
2216 //
2217 Status = UpdateVariableStore (
2219 FALSE,
2220 TRUE,
2221 Fvb,
2223 (UINT32)(VarSize - GetVariableHeaderSize (AuthFormat)),
2224 (UINT8 *)NextVariable + GetVariableHeaderSize (AuthFormat)
2225 );
2226
2227 if (EFI_ERROR (Status)) {
2228 goto Done;
2229 }
2230
2231 //
2232 // Step 4:
2233 //
2234 NextVariable->State = VAR_ADDED;
2235 Status = UpdateVariableStore (
2237 FALSE,
2238 TRUE,
2239 Fvb,
2240 mVariableModuleGlobal->NonVolatileLastVariableOffset + OFFSET_OF (VARIABLE_HEADER, State),
2241 sizeof (UINT8),
2242 &NextVariable->State
2243 );
2244
2245 if (EFI_ERROR (Status)) {
2246 goto Done;
2247 }
2248
2249 //
2250 // Update the memory copy of Flash region.
2251 //
2252 CopyMem ((UINT8 *)mNvVariableCache + mVariableModuleGlobal->NonVolatileLastVariableOffset, (UINT8 *)NextVariable, VarSize);
2253 } else {
2254 //
2255 // Emulated non-volatile variable mode.
2256 //
2257 NextVariable->State = VAR_ADDED;
2258 Status = UpdateVariableStore (
2260 FALSE,
2261 TRUE,
2262 Fvb,
2264 (UINT32)VarSize,
2265 (UINT8 *)NextVariable
2266 );
2267
2268 if (EFI_ERROR (Status)) {
2269 goto Done;
2270 }
2271 }
2272
2273 mVariableModuleGlobal->NonVolatileLastVariableOffset += HEADER_ALIGN (VarSize);
2274
2275 if ((Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) != 0) {
2276 mVariableModuleGlobal->HwErrVariableTotalSize += HEADER_ALIGN (VarSize);
2277 } else {
2278 mVariableModuleGlobal->CommonVariableTotalSize += HEADER_ALIGN (VarSize);
2279 if (IsCommonUserVariable) {
2280 mVariableModuleGlobal->CommonUserVariableTotalSize += HEADER_ALIGN (VarSize);
2281 }
2282 }
2283 } else {
2284 //
2285 // Create a volatile variable.
2286 //
2287 Volatile = TRUE;
2288
2289 if ((UINT32)(VarSize + mVariableModuleGlobal->VolatileLastVariableOffset) >
2290 ((VARIABLE_STORE_HEADER *)((UINTN)(mVariableModuleGlobal->VariableGlobal.VolatileVariableBase)))->Size)
2291 {
2292 //
2293 // Perform garbage collection & reclaim operation, and integrate the new variable at the same time.
2294 //
2295 Status = Reclaim (
2298 TRUE,
2299 Variable,
2300 NextVariable,
2301 HEADER_ALIGN (VarSize)
2302 );
2303 if (!EFI_ERROR (Status)) {
2304 //
2305 // The new variable has been integrated successfully during reclaiming.
2306 //
2307 if (Variable->CurrPtr != NULL) {
2308 CacheVariable->CurrPtr = (VARIABLE_HEADER *)((UINTN)CacheVariable->StartPtr + ((UINTN)Variable->CurrPtr - (UINTN)Variable->StartPtr));
2309 CacheVariable->InDeletedTransitionPtr = NULL;
2310 }
2311
2312 UpdateVariableInfo (VariableName, VendorGuid, TRUE, FALSE, TRUE, FALSE, FALSE, &gVariableInfo);
2313 }
2314
2315 goto Done;
2316 }
2317
2318 NextVariable->State = VAR_ADDED;
2319 Status = UpdateVariableStore (
2321 TRUE,
2322 TRUE,
2323 Fvb,
2325 (UINT32)VarSize,
2326 (UINT8 *)NextVariable
2327 );
2328
2329 if (EFI_ERROR (Status)) {
2330 goto Done;
2331 }
2332
2333 mVariableModuleGlobal->VolatileLastVariableOffset += HEADER_ALIGN (VarSize);
2334 }
2335
2336 //
2337 // Mark the old variable as deleted.
2338 //
2339 if (!EFI_ERROR (Status) && (Variable->CurrPtr != NULL)) {
2340 if (Variable->InDeletedTransitionPtr != NULL) {
2341 //
2342 // Both ADDED and IN_DELETED_TRANSITION old variable are present,
2343 // set IN_DELETED_TRANSITION one to DELETED state first.
2344 //
2345 ASSERT (CacheVariable->InDeletedTransitionPtr != NULL);
2346 State = CacheVariable->InDeletedTransitionPtr->State;
2347 State &= VAR_DELETED;
2348 Status = UpdateVariableStore (
2350 Variable->Volatile,
2351 FALSE,
2352 Fvb,
2353 (UINTN)&Variable->InDeletedTransitionPtr->State,
2354 sizeof (UINT8),
2355 &State
2356 );
2357 if (!EFI_ERROR (Status)) {
2358 if (!Variable->Volatile) {
2359 CacheVariable->InDeletedTransitionPtr->State = State;
2360 }
2361 } else {
2362 goto Done;
2363 }
2364 }
2365
2366 State = CacheVariable->CurrPtr->State;
2367 State &= VAR_DELETED;
2368
2369 Status = UpdateVariableStore (
2371 Variable->Volatile,
2372 FALSE,
2373 Fvb,
2374 (UINTN)&Variable->CurrPtr->State,
2375 sizeof (UINT8),
2376 &State
2377 );
2378 if (!EFI_ERROR (Status) && !Variable->Volatile) {
2379 CacheVariable->CurrPtr->State = State;
2380 }
2381 }
2382
2383 if (!EFI_ERROR (Status)) {
2384 UpdateVariableInfo (VariableName, VendorGuid, Volatile, FALSE, TRUE, FALSE, FALSE, &gVariableInfo);
2385 if (!Volatile) {
2386 FlushHobVariableToFlash (VariableName, VendorGuid);
2387 }
2388 }
2389
2390Done:
2391 if (!EFI_ERROR (Status)) {
2392 if (((Variable->CurrPtr != NULL) && !Variable->Volatile) || ((Attributes & EFI_VARIABLE_NON_VOLATILE) != 0)) {
2394 } else {
2396 }
2397
2398 if (VolatileCacheInstance->Store != NULL) {
2400 VolatileCacheInstance,
2401 0,
2402 VolatileCacheInstance->Store->Size
2403 );
2404 ASSERT_EFI_ERROR (Status);
2405 }
2406 }
2407
2408 return Status;
2409}
2410
2433EFI_STATUS
2434EFIAPI
2436 IN CHAR16 *VariableName,
2437 IN EFI_GUID *VendorGuid,
2438 OUT UINT32 *Attributes OPTIONAL,
2439 IN OUT UINTN *DataSize,
2440 OUT VOID *Data OPTIONAL
2441 )
2442{
2443 EFI_STATUS Status;
2444 VARIABLE_POINTER_TRACK Variable;
2445 UINTN VarDataSize;
2446
2447 if ((VariableName == NULL) || (VendorGuid == NULL) || (DataSize == NULL)) {
2448 return EFI_INVALID_PARAMETER;
2449 }
2450
2451 if (VariableName[0] == 0) {
2452 return EFI_NOT_FOUND;
2453 }
2454
2456
2457 Status = FindVariable (VariableName, VendorGuid, &Variable, &mVariableModuleGlobal->VariableGlobal, FALSE);
2458 if ((Variable.CurrPtr == NULL) || EFI_ERROR (Status)) {
2459 goto Done;
2460 }
2461
2462 //
2463 // Get data size
2464 //
2466 ASSERT (VarDataSize != 0);
2467
2468 if (*DataSize >= VarDataSize) {
2469 if (Data == NULL) {
2470 Status = EFI_INVALID_PARAMETER;
2471 goto Done;
2472 }
2473
2475
2476 *DataSize = VarDataSize;
2477 UpdateVariableInfo (VariableName, VendorGuid, Variable.Volatile, TRUE, FALSE, FALSE, FALSE, &gVariableInfo);
2478
2479 Status = EFI_SUCCESS;
2480 goto Done;
2481 } else {
2482 *DataSize = VarDataSize;
2483 Status = EFI_BUFFER_TOO_SMALL;
2484 goto Done;
2485 }
2486
2487Done:
2488 if ((Status == EFI_SUCCESS) || (Status == EFI_BUFFER_TOO_SMALL)) {
2489 if ((Attributes != NULL) && (Variable.CurrPtr != NULL)) {
2490 *Attributes = Variable.CurrPtr->Attributes;
2491 }
2492 }
2493
2495 return Status;
2496}
2497
2523EFI_STATUS
2524EFIAPI
2526 IN OUT UINTN *VariableNameSize,
2527 IN OUT CHAR16 *VariableName,
2528 IN OUT EFI_GUID *VendorGuid
2529 )
2530{
2531 EFI_STATUS Status;
2532 UINTN MaxLen;
2533 UINTN VarNameSize;
2534 BOOLEAN AuthFormat;
2535 VARIABLE_HEADER *VariablePtr;
2536 VARIABLE_STORE_HEADER *VariableStoreHeader[VariableStoreTypeMax];
2537
2538 if ((VariableNameSize == NULL) || (VariableName == NULL) || (VendorGuid == NULL)) {
2539 return EFI_INVALID_PARAMETER;
2540 }
2541
2543
2544 //
2545 // Calculate the possible maximum length of name string, including the Null terminator.
2546 //
2547 MaxLen = *VariableNameSize / sizeof (CHAR16);
2548 if ((MaxLen == 0) || (StrnLenS (VariableName, MaxLen) == MaxLen)) {
2549 //
2550 // Null-terminator is not found in the first VariableNameSize bytes of the input VariableName buffer,
2551 // follow spec to return EFI_INVALID_PARAMETER.
2552 //
2553 return EFI_INVALID_PARAMETER;
2554 }
2555
2557
2558 //
2559 // 0: Volatile, 1: HOB, 2: Non-Volatile.
2560 // The index and attributes mapping must be kept in this order as FindVariable
2561 // makes use of this mapping to implement search algorithm.
2562 //
2563 VariableStoreHeader[VariableStoreTypeVolatile] = (VARIABLE_STORE_HEADER *)(UINTN)mVariableModuleGlobal->VariableGlobal.VolatileVariableBase;
2564 VariableStoreHeader[VariableStoreTypeHob] = (VARIABLE_STORE_HEADER *)(UINTN)mVariableModuleGlobal->VariableGlobal.HobVariableBase;
2565 VariableStoreHeader[VariableStoreTypeNv] = mNvVariableCache;
2566
2568 VariableName,
2569 VendorGuid,
2570 VariableStoreHeader,
2571 &VariablePtr,
2572 AuthFormat
2573 );
2574 if (!EFI_ERROR (Status)) {
2575 VarNameSize = NameSizeOfVariable (VariablePtr, AuthFormat);
2576 ASSERT (VarNameSize != 0);
2577 if (VarNameSize <= *VariableNameSize) {
2578 CopyMem (
2579 VariableName,
2580 GetVariableNamePtr (VariablePtr, AuthFormat),
2581 VarNameSize
2582 );
2583 CopyMem (
2584 VendorGuid,
2585 GetVendorGuidPtr (VariablePtr, AuthFormat),
2586 sizeof (EFI_GUID)
2587 );
2588 Status = EFI_SUCCESS;
2589 } else {
2590 Status = EFI_BUFFER_TOO_SMALL;
2591 }
2592
2593 *VariableNameSize = VarNameSize;
2594 }
2595
2597 return Status;
2598}
2599
2625EFI_STATUS
2626EFIAPI
2628 IN CHAR16 *VariableName,
2629 IN EFI_GUID *VendorGuid,
2630 IN UINT32 Attributes,
2631 IN UINTN DataSize,
2632 IN VOID *Data
2633 )
2634{
2635 VARIABLE_POINTER_TRACK Variable;
2636 EFI_STATUS Status;
2637 VARIABLE_HEADER *NextVariable;
2638 EFI_PHYSICAL_ADDRESS Point;
2639 UINTN PayloadSize;
2640 BOOLEAN AuthFormat;
2641
2643
2644 //
2645 // Check input parameters.
2646 //
2647 if ((VariableName == NULL) || (VariableName[0] == 0) || (VendorGuid == NULL)) {
2648 return EFI_INVALID_PARAMETER;
2649 }
2650
2651 if ((DataSize != 0) && (Data == NULL)) {
2652 return EFI_INVALID_PARAMETER;
2653 }
2654
2655 //
2656 // Check for reserverd bit in variable attribute.
2657 // EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS is deprecated but we still allow
2658 // the delete operation of common authenticated variable at user physical presence.
2659 // So leave EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS attribute check to AuthVariableLib
2660 //
2661 if ((Attributes & (~(EFI_VARIABLE_ATTRIBUTES_MASK | EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS | EFI_VARIABLE_APPLE_BIT))) != 0) {
2662 return EFI_INVALID_PARAMETER;
2663 }
2664
2665 //
2666 // Check if the combination of attribute bits is valid.
2667 //
2668 if ((Attributes & (EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS)) == EFI_VARIABLE_RUNTIME_ACCESS) {
2669 //
2670 // Make sure if runtime bit is set, boot service bit is set also.
2671 //
2672 if ((Attributes & EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS) != 0) {
2673 return EFI_UNSUPPORTED;
2674 } else {
2675 return EFI_INVALID_PARAMETER;
2676 }
2677 } else if ((Attributes & EFI_VARIABLE_ATTRIBUTES_MASK) == EFI_VARIABLE_NON_VOLATILE) {
2678 //
2679 // Only EFI_VARIABLE_NON_VOLATILE attribute is invalid
2680 //
2681 return EFI_INVALID_PARAMETER;
2682 } else if ((Attributes & VARIABLE_ATTRIBUTE_AT_AW) != 0) {
2684 //
2685 // Not support authenticated variable write.
2686 //
2687 return EFI_INVALID_PARAMETER;
2688 }
2689 } else if ((Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) != 0) {
2690 if (PcdGet32 (PcdHwErrStorageSize) == 0) {
2691 //
2692 // Not support harware error record variable variable.
2693 //
2694 return EFI_INVALID_PARAMETER;
2695 }
2696 }
2697
2698 //
2699 // EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS and EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS attribute
2700 // cannot be set both.
2701 //
2702 if ( ((Attributes & EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS) == EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS)
2703 && ((Attributes & EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS) == EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS))
2704 {
2705 return EFI_UNSUPPORTED;
2706 }
2707
2708 if ((Attributes & EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS) == EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS) {
2709 //
2710 // If DataSize == AUTHINFO_SIZE and then PayloadSize is 0.
2711 // Maybe it's the delete operation of common authenticated variable at user physical presence.
2712 //
2713 if (DataSize != AUTHINFO_SIZE) {
2714 return EFI_UNSUPPORTED;
2715 }
2716
2717 PayloadSize = DataSize - AUTHINFO_SIZE;
2718 } else if ((Attributes & EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS) == EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS) {
2719 //
2720 // Sanity check for EFI_VARIABLE_AUTHENTICATION_2 descriptor.
2721 //
2722 if ((DataSize < OFFSET_OF_AUTHINFO2_CERT_DATA) ||
2723 (((EFI_VARIABLE_AUTHENTICATION_2 *)Data)->AuthInfo.Hdr.dwLength > DataSize - (OFFSET_OF (EFI_VARIABLE_AUTHENTICATION_2, AuthInfo))) ||
2724 (((EFI_VARIABLE_AUTHENTICATION_2 *)Data)->AuthInfo.Hdr.dwLength < OFFSET_OF (WIN_CERTIFICATE_UEFI_GUID, CertData)))
2725 {
2726 return EFI_SECURITY_VIOLATION;
2727 }
2728
2729 //
2730 // The VariableSpeculationBarrier() call here is to ensure the above sanity
2731 // check for the EFI_VARIABLE_AUTHENTICATION_2 descriptor has been completed
2732 // before the execution of subsequent codes.
2733 //
2735 PayloadSize = DataSize - AUTHINFO2_SIZE (Data);
2736 } else {
2737 PayloadSize = DataSize;
2738 }
2739
2740 if ((UINTN)(~0) - PayloadSize < StrSize (VariableName)) {
2741 //
2742 // Prevent whole variable size overflow
2743 //
2744 return EFI_INVALID_PARAMETER;
2745 }
2746
2747 //
2748 // The size of the VariableName, including the Unicode Null in bytes plus
2749 // the DataSize is limited to maximum size of PcdGet32 (PcdMaxHardwareErrorVariableSize)
2750 // bytes for HwErrRec#### variable.
2751 //
2752 if ((Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == EFI_VARIABLE_HARDWARE_ERROR_RECORD) {
2753 if (StrSize (VariableName) + PayloadSize >
2754 PcdGet32 (PcdMaxHardwareErrorVariableSize) - GetVariableHeaderSize (AuthFormat))
2755 {
2756 return EFI_INVALID_PARAMETER;
2757 }
2758 } else {
2759 //
2760 // The size of the VariableName, including the Unicode Null in bytes plus
2761 // the DataSize is limited to maximum size of Max(Auth|Volatile)VariableSize bytes.
2762 //
2763 if ((Attributes & VARIABLE_ATTRIBUTE_AT_AW) != 0) {
2764 if (StrSize (VariableName) + PayloadSize >
2766 GetVariableHeaderSize (AuthFormat))
2767 {
2768 DEBUG ((
2769 DEBUG_ERROR,
2770 "%a: Failed to set variable '%s' with Guid %g\n",
2771 __FUNCTION__,
2772 VariableName,
2773 VendorGuid
2774 ));
2775 DEBUG ((
2776 DEBUG_ERROR,
2777 "NameSize(0x%x) + PayloadSize(0x%x) > "
2778 "MaxAuthVariableSize(0x%x) - HeaderSize(0x%x)\n",
2779 StrSize (VariableName),
2780 PayloadSize,
2782 GetVariableHeaderSize (AuthFormat)
2783 ));
2784 return EFI_INVALID_PARAMETER;
2785 }
2786 } else if ((Attributes & EFI_VARIABLE_NON_VOLATILE) != 0) {
2787 if (StrSize (VariableName) + PayloadSize >
2789 {
2790 DEBUG ((
2791 DEBUG_ERROR,
2792 "%a: Failed to set variable '%s' with Guid %g\n",
2793 __FUNCTION__,
2794 VariableName,
2795 VendorGuid
2796 ));
2797 DEBUG ((
2798 DEBUG_ERROR,
2799 "NameSize(0x%x) + PayloadSize(0x%x) > "
2800 "MaxVariableSize(0x%x) - HeaderSize(0x%x)\n",
2801 StrSize (VariableName),
2802 PayloadSize,
2804 GetVariableHeaderSize (AuthFormat)
2805 ));
2806 return EFI_INVALID_PARAMETER;
2807 }
2808 } else {
2809 if (StrSize (VariableName) + PayloadSize >
2811 {
2812 DEBUG ((
2813 DEBUG_ERROR,
2814 "%a: Failed to set variable '%s' with Guid %g\n",
2815 __FUNCTION__,
2816 VariableName,
2817 VendorGuid
2818 ));
2819 DEBUG ((
2820 DEBUG_ERROR,
2821 "NameSize(0x%x) + PayloadSize(0x%x) > "
2822 "MaxVolatileVariableSize(0x%x) - HeaderSize(0x%x)\n",
2823 StrSize (VariableName),
2824 PayloadSize,
2826 GetVariableHeaderSize (AuthFormat)
2827 ));
2828 return EFI_INVALID_PARAMETER;
2829 }
2830 }
2831 }
2832
2833 //
2834 // Special Handling for MOR Lock variable.
2835 //
2836 Status = SetVariableCheckHandlerMor (VariableName, VendorGuid, Attributes, PayloadSize, (VOID *)((UINTN)Data + DataSize - PayloadSize));
2837 if (Status == EFI_ALREADY_STARTED) {
2838 //
2839 // EFI_ALREADY_STARTED means the SetVariable() action is handled inside of SetVariableCheckHandlerMor().
2840 // Variable driver can just return SUCCESS.
2841 //
2842 return EFI_SUCCESS;
2843 }
2844
2845 if (EFI_ERROR (Status)) {
2846 return Status;
2847 }
2848
2849 Status = VarCheckLibSetVariableCheck (VariableName, VendorGuid, Attributes, PayloadSize, (VOID *)((UINTN)Data + DataSize - PayloadSize), mRequestSource);
2850 if (EFI_ERROR (Status)) {
2851 return Status;
2852 }
2853
2855
2856 //
2857 // Consider reentrant in MCA/INIT/NMI. It needs be reupdated.
2858 //
2859 if (1 < InterlockedIncrement (&mVariableModuleGlobal->VariableGlobal.ReentrantState)) {
2861 //
2862 // Parse non-volatile variable data and get last variable offset.
2863 //
2864 NextVariable = GetStartPointer ((VARIABLE_STORE_HEADER *)(UINTN)Point);
2865 while (IsValidVariableHeader (NextVariable, GetEndPointer ((VARIABLE_STORE_HEADER *)(UINTN)Point))) {
2866 NextVariable = GetNextVariablePtr (NextVariable, AuthFormat);
2867 }
2868
2869 mVariableModuleGlobal->NonVolatileLastVariableOffset = (UINTN)NextVariable - (UINTN)Point;
2870 }
2871
2872 //
2873 // Check whether the input variable is already existed.
2874 //
2875 Status = FindVariable (VariableName, VendorGuid, &Variable, &mVariableModuleGlobal->VariableGlobal, TRUE);
2876 if (!EFI_ERROR (Status)) {
2877 if (((Variable.CurrPtr->Attributes & EFI_VARIABLE_RUNTIME_ACCESS) == 0) && AtRuntime ()) {
2878 Status = EFI_WRITE_PROTECTED;
2879 goto Done;
2880 }
2881
2882 if ((Attributes != 0) && ((Attributes & (~EFI_VARIABLE_APPEND_WRITE)) != Variable.CurrPtr->Attributes)) {
2883 //
2884 // If a preexisting variable is rewritten with different attributes, SetVariable() shall not
2885 // modify the variable and shall return EFI_INVALID_PARAMETER. Two exceptions to this rule:
2886 // 1. No access attributes specified
2887 // 2. The only attribute differing is EFI_VARIABLE_APPEND_WRITE
2888 //
2889 Status = EFI_INVALID_PARAMETER;
2890 DEBUG ((DEBUG_INFO, "[Variable]: Rewritten a preexisting variable(0x%08x) with different attributes(0x%08x) - %g:%s\n", Variable.CurrPtr->Attributes, Attributes, VendorGuid, VariableName));
2891 goto Done;
2892 }
2893 }
2894
2895 if (!FeaturePcdGet (PcdUefiVariableDefaultLangDeprecate)) {
2896 //
2897 // Hook the operation of setting PlatformLangCodes/PlatformLang and LangCodes/Lang.
2898 //
2899 Status = AutoUpdateLangVariable (VariableName, Data, DataSize);
2900 if (EFI_ERROR (Status)) {
2901 //
2902 // The auto update operation failed, directly return to avoid inconsistency between PlatformLang and Lang.
2903 //
2904 goto Done;
2905 }
2906 }
2907
2909 Status = AuthVariableLibProcessVariable (VariableName, VendorGuid, Data, DataSize, Attributes);
2910 } else {
2911 Status = UpdateVariable (VariableName, VendorGuid, Data, DataSize, Attributes, 0, 0, &Variable, NULL);
2912 }
2913
2914Done:
2915 InterlockedDecrement (&mVariableModuleGlobal->VariableGlobal.ReentrantState);
2917
2918 if (!AtRuntime ()) {
2919 if (!EFI_ERROR (Status)) {
2921 VariableName,
2922 VendorGuid
2923 );
2924 }
2925 }
2926
2927 return Status;
2928}
2929
2949EFI_STATUS
2950EFIAPI
2952 IN UINT32 Attributes,
2953 OUT UINT64 *MaximumVariableStorageSize,
2954 OUT UINT64 *RemainingVariableStorageSize,
2955 OUT UINT64 *MaximumVariableSize
2956 )
2957{
2958 VARIABLE_HEADER *Variable;
2959 VARIABLE_HEADER *NextVariable;
2960 UINT64 VariableSize;
2961 VARIABLE_STORE_HEADER *VariableStoreHeader;
2962 UINT64 CommonVariableTotalSize;
2963 UINT64 HwErrVariableTotalSize;
2964 EFI_STATUS Status;
2965 VARIABLE_POINTER_TRACK VariablePtrTrack;
2966
2967 CommonVariableTotalSize = 0;
2968 HwErrVariableTotalSize = 0;
2969
2970 if ((Attributes & EFI_VARIABLE_NON_VOLATILE) == 0) {
2971 //
2972 // Query is Volatile related.
2973 //
2974 VariableStoreHeader = (VARIABLE_STORE_HEADER *)((UINTN)mVariableModuleGlobal->VariableGlobal.VolatileVariableBase);
2975 } else {
2976 //
2977 // Query is Non-Volatile related.
2978 //
2979 VariableStoreHeader = mNvVariableCache;
2980 }
2981
2982 //
2983 // Now let's fill *MaximumVariableStorageSize *RemainingVariableStorageSize
2984 // with the storage size (excluding the storage header size).
2985 //
2986 *MaximumVariableStorageSize = VariableStoreHeader->Size - sizeof (VARIABLE_STORE_HEADER);
2987
2988 //
2989 // Harware error record variable needs larger size.
2990 //
2991 if ((Attributes & (EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_HARDWARE_ERROR_RECORD)) == (EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_HARDWARE_ERROR_RECORD)) {
2992 *MaximumVariableStorageSize = PcdGet32 (PcdHwErrStorageSize);
2993 *MaximumVariableSize = PcdGet32 (PcdMaxHardwareErrorVariableSize) -
2995 } else {
2996 if ((Attributes & EFI_VARIABLE_NON_VOLATILE) != 0) {
2997 if (AtRuntime ()) {
2998 *MaximumVariableStorageSize = mVariableModuleGlobal->CommonRuntimeVariableSpace;
2999 } else {
3000 *MaximumVariableStorageSize = mVariableModuleGlobal->CommonVariableSpace;
3001 }
3002 }
3003
3004 //
3005 // Let *MaximumVariableSize be Max(Auth|Volatile)VariableSize with the exception of the variable header size.
3006 //
3007 if ((Attributes & VARIABLE_ATTRIBUTE_AT_AW) != 0) {
3008 *MaximumVariableSize = mVariableModuleGlobal->MaxAuthVariableSize -
3010 } else if ((Attributes & EFI_VARIABLE_NON_VOLATILE) != 0) {
3011 *MaximumVariableSize = mVariableModuleGlobal->MaxVariableSize -
3013 } else {
3014 *MaximumVariableSize = mVariableModuleGlobal->MaxVolatileVariableSize -
3016 }
3017 }
3018
3019 //
3020 // Point to the starting address of the variables.
3021 //
3022 Variable = GetStartPointer (VariableStoreHeader);
3023
3024 //
3025 // Now walk through the related variable store.
3026 //
3027 while (IsValidVariableHeader (Variable, GetEndPointer (VariableStoreHeader))) {
3029 VariableSize = (UINT64)(UINTN)NextVariable - (UINT64)(UINTN)Variable;
3030
3031 if (AtRuntime ()) {
3032 //
3033 // We don't take the state of the variables in mind
3034 // when calculating RemainingVariableStorageSize,
3035 // since the space occupied by variables not marked with
3036 // VAR_ADDED is not allowed to be reclaimed in Runtime.
3037 //
3038 if ((Variable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == EFI_VARIABLE_HARDWARE_ERROR_RECORD) {
3039 HwErrVariableTotalSize += VariableSize;
3040 } else {
3041 CommonVariableTotalSize += VariableSize;
3042 }
3043 } else {
3044 //
3045 // Only care about Variables with State VAR_ADDED, because
3046 // the space not marked as VAR_ADDED is reclaimable now.
3047 //
3048 if (Variable->State == VAR_ADDED) {
3049 if ((Variable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == EFI_VARIABLE_HARDWARE_ERROR_RECORD) {
3050 HwErrVariableTotalSize += VariableSize;
3051 } else {
3052 CommonVariableTotalSize += VariableSize;
3053 }
3054 } else if (Variable->State == (VAR_IN_DELETED_TRANSITION & VAR_ADDED)) {
3055 //
3056 // If it is a IN_DELETED_TRANSITION variable,
3057 // and there is not also a same ADDED one at the same time,
3058 // this IN_DELETED_TRANSITION variable is valid.
3059 //
3060 VariablePtrTrack.StartPtr = GetStartPointer (VariableStoreHeader);
3061 VariablePtrTrack.EndPtr = GetEndPointer (VariableStoreHeader);
3062 Status = FindVariableEx (
3065 FALSE,
3066 &VariablePtrTrack,
3068 );
3069 if (!EFI_ERROR (Status) && (VariablePtrTrack.CurrPtr->State != VAR_ADDED)) {
3070 if ((Variable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == EFI_VARIABLE_HARDWARE_ERROR_RECORD) {
3071 HwErrVariableTotalSize += VariableSize;
3072 } else {
3073 CommonVariableTotalSize += VariableSize;
3074 }
3075 }
3076 }
3077 }
3078
3079 //
3080 // Go to the next one.
3081 //
3082 Variable = NextVariable;
3083 }
3084
3085 if ((Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == EFI_VARIABLE_HARDWARE_ERROR_RECORD) {
3086 *RemainingVariableStorageSize = *MaximumVariableStorageSize - HwErrVariableTotalSize;
3087 } else {
3088 if (*MaximumVariableStorageSize < CommonVariableTotalSize) {
3089 *RemainingVariableStorageSize = 0;
3090 } else {
3091 *RemainingVariableStorageSize = *MaximumVariableStorageSize - CommonVariableTotalSize;
3092 }
3093 }
3094
3095 if (*RemainingVariableStorageSize < GetVariableHeaderSize (mVariableModuleGlobal->VariableGlobal.AuthFormat)) {
3096 *MaximumVariableSize = 0;
3097 } else if ((*RemainingVariableStorageSize - GetVariableHeaderSize (mVariableModuleGlobal->VariableGlobal.AuthFormat)) <
3098 *MaximumVariableSize
3099 )
3100 {
3101 *MaximumVariableSize = *RemainingVariableStorageSize -
3103 }
3104
3105 return EFI_SUCCESS;
3106}
3107
3129EFI_STATUS
3130EFIAPI
3132 IN UINT32 Attributes,
3133 OUT UINT64 *MaximumVariableStorageSize,
3134 OUT UINT64 *RemainingVariableStorageSize,
3135 OUT UINT64 *MaximumVariableSize
3136 )
3137{
3138 EFI_STATUS Status;
3139
3140 if ((MaximumVariableStorageSize == NULL) || (RemainingVariableStorageSize == NULL) || (MaximumVariableSize == NULL) || (Attributes == 0)) {
3141 return EFI_INVALID_PARAMETER;
3142 }
3143
3144 if ((Attributes & EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS) != 0) {
3145 //
3146 // Deprecated attribute, make this check as highest priority.
3147 //
3148 return EFI_UNSUPPORTED;
3149 }
3150
3151 if ((Attributes & EFI_VARIABLE_ATTRIBUTES_MASK) == 0) {
3152 //
3153 // Make sure the Attributes combination is supported by the platform.
3154 //
3155 return EFI_UNSUPPORTED;
3156 } else if ((Attributes & EFI_VARIABLE_ATTRIBUTES_MASK) == EFI_VARIABLE_NON_VOLATILE) {
3157 //
3158 // Only EFI_VARIABLE_NON_VOLATILE attribute is invalid
3159 //
3160 return EFI_INVALID_PARAMETER;
3161 } else if ((Attributes & (EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS)) == EFI_VARIABLE_RUNTIME_ACCESS) {
3162 //
3163 // Make sure if runtime bit is set, boot service bit is set also.
3164 //
3165 return EFI_INVALID_PARAMETER;
3166 } else if (AtRuntime () && ((Attributes & EFI_VARIABLE_RUNTIME_ACCESS) == 0)) {
3167 //
3168 // Make sure RT Attribute is set if we are in Runtime phase.
3169 //
3170 return EFI_INVALID_PARAMETER;
3171 } else if ((Attributes & (EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_HARDWARE_ERROR_RECORD)) == EFI_VARIABLE_HARDWARE_ERROR_RECORD) {
3172 //
3173 // Make sure Hw Attribute is set with NV.
3174 //
3175 return EFI_INVALID_PARAMETER;
3176 } else if ((Attributes & VARIABLE_ATTRIBUTE_AT_AW) != 0) {
3178 //
3179 // Not support authenticated variable write.
3180 //
3181 return EFI_UNSUPPORTED;
3182 }
3183 } else if ((Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) != 0) {
3184 if (PcdGet32 (PcdHwErrStorageSize) == 0) {
3185 //
3186 // Not support harware error record variable variable.
3187 //
3188 return EFI_UNSUPPORTED;
3189 }
3190 }
3191
3193
3195 Attributes,
3196 MaximumVariableStorageSize,
3197 RemainingVariableStorageSize,
3198 MaximumVariableSize
3199 );
3200
3202 return Status;
3203}
3204
3212VOID
3214 VOID
3215 )
3216{
3217 EFI_STATUS Status;
3218 UINTN RemainingCommonRuntimeVariableSpace;
3219 UINTN RemainingHwErrVariableSpace;
3220 STATIC BOOLEAN Reclaimed;
3221
3222 //
3223 // This function will be called only once at EndOfDxe or ReadyToBoot event.
3224 //
3225 if (Reclaimed) {
3226 return;
3227 }
3228
3229 Reclaimed = TRUE;
3230
3231 Status = EFI_SUCCESS;
3232
3234 RemainingCommonRuntimeVariableSpace = 0;
3235 } else {
3237 }
3238
3239 RemainingHwErrVariableSpace = PcdGet32 (PcdHwErrStorageSize) - mVariableModuleGlobal->HwErrVariableTotalSize;
3240
3241 //
3242 // Check if the free area is below a threshold.
3243 //
3244 if (((RemainingCommonRuntimeVariableSpace < mVariableModuleGlobal->MaxVariableSize) ||
3245 (RemainingCommonRuntimeVariableSpace < mVariableModuleGlobal->MaxAuthVariableSize)) ||
3246 ((PcdGet32 (PcdHwErrStorageSize) != 0) &&
3247 (RemainingHwErrVariableSpace < PcdGet32 (PcdMaxHardwareErrorVariableSize))))
3248 {
3249 Status = Reclaim (
3252 FALSE,
3253 NULL,
3254 NULL,
3255 0
3256 );
3257 ASSERT_EFI_ERROR (Status);
3258 }
3259}
3260
3267UINTN
3269 VOID
3270 )
3271{
3272 UINTN MaxVariableSize;
3273
3274 MaxVariableSize = GetNonVolatileMaxVariableSize ();
3275 //
3276 // The condition below fails implicitly if PcdMaxVolatileVariableSize equals
3277 // the default zero value.
3278 //
3279 if (MaxVariableSize < PcdGet32 (PcdMaxVolatileVariableSize)) {
3280 MaxVariableSize = PcdGet32 (PcdMaxVolatileVariableSize);
3281 }
3282
3283 return MaxVariableSize;
3284}
3285
3293VOID
3295 IN CHAR16 *VariableName,
3296 IN EFI_GUID *VendorGuid
3297 )
3298{
3299 EFI_STATUS Status;
3300 VARIABLE_STORE_HEADER *VariableStoreHeader;
3301 VARIABLE_HEADER *Variable;
3302 VOID *VariableData;
3303 VARIABLE_POINTER_TRACK VariablePtrTrack;
3304 BOOLEAN ErrorFlag;
3305 BOOLEAN AuthFormat;
3306
3307 ErrorFlag = FALSE;
3309
3310 //
3311 // Flush the HOB variable to flash.
3312 //
3314 VariableStoreHeader = (VARIABLE_STORE_HEADER *)(UINTN)mVariableModuleGlobal->VariableGlobal.HobVariableBase;
3315 //
3316 // Set HobVariableBase to 0, it can avoid SetVariable to call back.
3317 //
3319 for ( Variable = GetStartPointer (VariableStoreHeader)
3320 ; IsValidVariableHeader (Variable, GetEndPointer (VariableStoreHeader))
3321 ; Variable = GetNextVariablePtr (Variable, AuthFormat)
3322 )
3323 {
3324 if (Variable->State != VAR_ADDED) {
3325 //
3326 // The HOB variable has been set to DELETED state in local.
3327 //
3328 continue;
3329 }
3330
3331 ASSERT ((Variable->Attributes & EFI_VARIABLE_NON_VOLATILE) != 0);
3332 if ((VendorGuid == NULL) || (VariableName == NULL) ||
3333 !CompareGuid (VendorGuid, GetVendorGuidPtr (Variable, AuthFormat)) ||
3334 (StrCmp (VariableName, GetVariableNamePtr (Variable, AuthFormat)) != 0))
3335 {
3336 VariableData = GetVariableDataPtr (Variable, AuthFormat);
3337 FindVariable (
3338 GetVariableNamePtr (Variable, AuthFormat),
3339 GetVendorGuidPtr (Variable, AuthFormat),
3340 &VariablePtrTrack,
3342 FALSE
3343 );
3344 Status = UpdateVariable (
3345 GetVariableNamePtr (Variable, AuthFormat),
3346 GetVendorGuidPtr (Variable, AuthFormat),
3347 VariableData,
3348 DataSizeOfVariable (Variable, AuthFormat),
3349 Variable->Attributes,
3350 0,
3351 0,
3352 &VariablePtrTrack,
3353 NULL
3354 );
3355 DEBUG ((
3356 DEBUG_INFO,
3357 "Variable driver flush the HOB variable to flash: %g %s %r\n",
3358 GetVendorGuidPtr (Variable, AuthFormat),
3359 GetVariableNamePtr (Variable, AuthFormat),
3360 Status
3361 ));
3362 } else {
3363 //
3364 // The updated or deleted variable is matched with this HOB variable.
3365 // Don't break here because we will try to set other HOB variables
3366 // since this variable could be set successfully.
3367 //
3368 Status = EFI_SUCCESS;
3369 }
3370
3371 if (!EFI_ERROR (Status)) {
3372 //
3373 // If set variable successful, or the updated or deleted variable is matched with the HOB variable,
3374 // set the HOB variable to DELETED state in local.
3375 //
3376 DEBUG ((
3377 DEBUG_INFO,
3378 "Variable driver set the HOB variable to DELETED state in local: %g %s\n",
3379 GetVendorGuidPtr (Variable, AuthFormat),
3380 GetVariableNamePtr (Variable, AuthFormat)
3381 ));
3382 Variable->State &= VAR_DELETED;
3383 } else {
3384 ErrorFlag = TRUE;
3385 }
3386 }
3387
3391 0,
3393 );
3394 ASSERT_EFI_ERROR (Status);
3395 }
3396
3397 if (ErrorFlag) {
3398 //
3399 // We still have HOB variable(s) not flushed in flash.
3400 //
3401 mVariableModuleGlobal->VariableGlobal.HobVariableBase = (EFI_PHYSICAL_ADDRESS)(UINTN)VariableStoreHeader;
3402 } else {
3403 //
3404 // All HOB variables have been flushed in flash.
3405 //
3406 DEBUG ((DEBUG_INFO, "Variable driver: all HOB variables have been flushed in flash.\n"));
3409 }
3410
3411 if (!AtRuntime ()) {
3412 FreePool ((VOID *)VariableStoreHeader);
3413 }
3414 }
3415 }
3416}
3417
3425EFI_STATUS
3427 VOID
3428 )
3429{
3430 EFI_STATUS Status;
3431 UINTN Index;
3432 UINT8 Data;
3433 VARIABLE_ENTRY_PROPERTY *VariableEntry;
3434
3436
3437 //
3438 // Check if the free area is really free.
3439 //
3440 for (Index = mVariableModuleGlobal->NonVolatileLastVariableOffset; Index < mNvVariableCache->Size; Index++) {
3441 Data = ((UINT8 *)mNvVariableCache)[Index];
3442 if (Data != 0xff) {
3443 //
3444 // There must be something wrong in variable store, do reclaim operation.
3445 //
3446 Status = Reclaim (
3449 FALSE,
3450 NULL,
3451 NULL,
3452 0
3453 );
3454 if (EFI_ERROR (Status)) {
3456 return Status;
3457 }
3458
3459 break;
3460 }
3461 }
3462
3463 FlushHobVariableToFlash (NULL, NULL);
3464
3465 Status = EFI_SUCCESS;
3468 //
3469 // Authenticated variable initialize.
3470 //
3471 mAuthContextIn.StructSize = sizeof (AUTH_VAR_LIB_CONTEXT_IN);
3474 Status = AuthVariableLibInitialize (&mAuthContextIn, &mAuthContextOut);
3475 if (!EFI_ERROR (Status)) {
3476 DEBUG ((DEBUG_INFO, "Variable driver will work with auth variable support!\n"));
3478 if (mAuthContextOut.AuthVarEntry != NULL) {
3479 for (Index = 0; Index < mAuthContextOut.AuthVarEntryCount; Index++) {
3480 VariableEntry = &mAuthContextOut.AuthVarEntry[Index];
3481 Status = VarCheckLibVariablePropertySet (
3482 VariableEntry->Name,
3483 VariableEntry->Guid,
3484 &VariableEntry->VariableProperty
3485 );
3486 ASSERT_EFI_ERROR (Status);
3487 }
3488 }
3489 } else if (Status == EFI_UNSUPPORTED) {
3490 DEBUG ((DEBUG_INFO, "NOTICE - AuthVariableLibInitialize() returns %r!\n", Status));
3491 DEBUG ((DEBUG_INFO, "Variable driver will continue to work without auth variable support!\n"));
3493 Status = EFI_SUCCESS;
3494 }
3495 }
3496
3497 if (!EFI_ERROR (Status)) {
3498 for (Index = 0; Index < ARRAY_SIZE (mVariableEntryProperty); Index++) {
3499 VariableEntry = &mVariableEntryProperty[Index];
3500 Status = VarCheckLibVariablePropertySet (VariableEntry->Name, VariableEntry->Guid, &VariableEntry->VariableProperty);
3501 ASSERT_EFI_ERROR (Status);
3502 }
3503 }
3504
3506
3507 //
3508 // Initialize MOR Lock variable.
3509 //
3510 MorLockInit ();
3511
3512 return Status;
3513}
3514
3522VOID *
3524 VARIABLE_STORE_HEADER *NormalVarStorage
3525 )
3526{
3527 VARIABLE_HEADER *StartPtr;
3528 UINT8 *NextPtr;
3529 VARIABLE_HEADER *EndPtr;
3530 UINTN AuthVarStroageSize;
3531 AUTHENTICATED_VARIABLE_HEADER *AuthStartPtr;
3532 VARIABLE_STORE_HEADER *AuthVarStorage;
3533
3534 AuthVarStroageSize = sizeof (VARIABLE_STORE_HEADER);
3535 //
3536 // Set AuthFormat as FALSE for normal variable storage
3537 //
3539
3540 //
3541 // Calculate Auth Variable Storage Size
3542 //
3543 StartPtr = GetStartPointer (NormalVarStorage);
3544 EndPtr = GetEndPointer (NormalVarStorage);
3545 while (StartPtr < EndPtr) {
3546 if (StartPtr->State == VAR_ADDED) {
3547 AuthVarStroageSize = HEADER_ALIGN (AuthVarStroageSize);
3548 AuthVarStroageSize += sizeof (AUTHENTICATED_VARIABLE_HEADER);
3549 AuthVarStroageSize += StartPtr->NameSize + GET_PAD_SIZE (StartPtr->NameSize);
3550 AuthVarStroageSize += StartPtr->DataSize + GET_PAD_SIZE (StartPtr->DataSize);
3551 }
3552
3554 }
3555
3556 //
3557 // Allocate Runtime memory for Auth Variable Storage
3558 //
3559 AuthVarStorage = AllocateRuntimeZeroPool (AuthVarStroageSize);
3560 ASSERT (AuthVarStorage != NULL);
3561 if (AuthVarStorage == NULL) {
3562 return NULL;
3563 }
3564
3565 //
3566 // Copy Variable from Normal storage to Auth storage
3567 //
3568 StartPtr = GetStartPointer (NormalVarStorage);
3569 EndPtr = GetEndPointer (NormalVarStorage);
3570 AuthStartPtr = (AUTHENTICATED_VARIABLE_HEADER *)GetStartPointer (AuthVarStorage);
3571 while (StartPtr < EndPtr) {
3572 if (StartPtr->State == VAR_ADDED) {
3573 AuthStartPtr = (AUTHENTICATED_VARIABLE_HEADER *)HEADER_ALIGN (AuthStartPtr);
3574 //
3575 // Copy Variable Header
3576 //
3577 AuthStartPtr->StartId = StartPtr->StartId;
3578 AuthStartPtr->State = StartPtr->State;
3579 AuthStartPtr->Attributes = StartPtr->Attributes;
3580 AuthStartPtr->NameSize = StartPtr->NameSize;
3581 AuthStartPtr->DataSize = StartPtr->DataSize;
3582 CopyGuid (&AuthStartPtr->VendorGuid, &StartPtr->VendorGuid);
3583 //
3584 // Copy Variable Name
3585 //
3586 NextPtr = (UINT8 *)(AuthStartPtr + 1);
3587 CopyMem (
3588 NextPtr,
3590 AuthStartPtr->NameSize
3591 );
3592 //
3593 // Copy Variable Data
3594 //
3595 NextPtr = NextPtr + AuthStartPtr->NameSize + GET_PAD_SIZE (AuthStartPtr->NameSize);
3596 CopyMem (NextPtr, GetVariableDataPtr (StartPtr, mVariableModuleGlobal->VariableGlobal.AuthFormat), AuthStartPtr->DataSize);
3597 //
3598 // Go to next variable
3599 //
3600 AuthStartPtr = (AUTHENTICATED_VARIABLE_HEADER *)(NextPtr + AuthStartPtr->DataSize + GET_PAD_SIZE (AuthStartPtr->DataSize));
3601 }
3602
3604 }
3605
3606 //
3607 // Update Auth Storage Header
3608 //
3609 AuthVarStorage->Format = NormalVarStorage->Format;
3610 AuthVarStorage->State = NormalVarStorage->State;
3611 AuthVarStorage->Size = (UINT32)((UINTN)AuthStartPtr - (UINTN)AuthVarStorage);
3612 CopyGuid (&AuthVarStorage->Signature, &gEfiAuthenticatedVariableGuid);
3613 ASSERT (AuthVarStorage->Size <= AuthVarStroageSize);
3614
3615 //
3616 // Restore AuthFormat
3617 //
3619 return AuthVarStorage;
3620}
3621
3631EFI_STATUS
3633 IN EFI_GUID *VariableGuid
3634 )
3635{
3636 VARIABLE_STORE_HEADER *VariableStoreHeader;
3637 UINT64 VariableStoreLength;
3638 EFI_HOB_GUID_TYPE *GuidHob;
3639 BOOLEAN NeedConvertNormalToAuth;
3640
3641 //
3642 // Make sure there is no more than one Variable HOB.
3643 //
3644 DEBUG_CODE_BEGIN ();
3645 GuidHob = GetFirstGuidHob (&gEfiAuthenticatedVariableGuid);
3646 if (GuidHob != NULL) {
3647 if ((GetNextGuidHob (&gEfiAuthenticatedVariableGuid, GET_NEXT_HOB (GuidHob)) != NULL)) {
3648 DEBUG ((DEBUG_ERROR, "ERROR: Found two Auth Variable HOBs\n"));
3649 ASSERT (FALSE);
3650 } else if (GetFirstGuidHob (&gEfiVariableGuid) != NULL) {
3651 DEBUG ((DEBUG_ERROR, "ERROR: Found one Auth + one Normal Variable HOBs\n"));
3652 ASSERT (FALSE);
3653 }
3654 } else {
3655 GuidHob = GetFirstGuidHob (&gEfiVariableGuid);
3656 if (GuidHob != NULL) {
3657 if ((GetNextGuidHob (&gEfiVariableGuid, GET_NEXT_HOB (GuidHob)) != NULL)) {
3658 DEBUG ((DEBUG_ERROR, "ERROR: Found two Normal Variable HOBs\n"));
3659 ASSERT (FALSE);
3660 }
3661 }
3662 }
3663
3664 DEBUG_CODE_END ();
3665
3666 //
3667 // Combinations supported:
3668 // 1. Normal NV variable store +
3669 // Normal HOB variable store
3670 // 2. Auth NV variable store +
3671 // Auth HOB variable store
3672 // 3. Auth NV variable store +
3673 // Normal HOB variable store (code will convert it to Auth Format)
3674 //
3675 NeedConvertNormalToAuth = FALSE;
3676 GuidHob = GetFirstGuidHob (VariableGuid);
3677 if ((GuidHob == NULL) && (VariableGuid == &gEfiAuthenticatedVariableGuid)) {
3678 //
3679 // Try getting it from normal variable HOB
3680 //
3681 GuidHob = GetFirstGuidHob (&gEfiVariableGuid);
3682 NeedConvertNormalToAuth = TRUE;
3683 }
3684
3685 if (GuidHob != NULL) {
3686 VariableStoreHeader = GET_GUID_HOB_DATA (GuidHob);
3687 VariableStoreLength = GuidHob->Header.HobLength - sizeof (EFI_HOB_GUID_TYPE);
3688 if (GetVariableStoreStatus (VariableStoreHeader) == EfiValid) {
3689 if (!NeedConvertNormalToAuth) {
3690 mVariableModuleGlobal->VariableGlobal.HobVariableBase = (EFI_PHYSICAL_ADDRESS)(UINTN)AllocateRuntimeCopyPool ((UINTN)VariableStoreLength, (VOID *)VariableStoreHeader);
3691 } else {
3692 mVariableModuleGlobal->VariableGlobal.HobVariableBase = (EFI_PHYSICAL_ADDRESS)(UINTN)ConvertNormalVarStorageToAuthVarStorage ((VOID *)VariableStoreHeader);
3693 }
3694
3696 return EFI_OUT_OF_RESOURCES;
3697 }
3698 } else {
3699 DEBUG ((DEBUG_ERROR, "HOB Variable Store header is corrupted!\n"));
3700 }
3701 }
3702
3703 return EFI_SUCCESS;
3704}
3705
3713EFI_STATUS
3715 VOID
3716 )
3717{
3718 EFI_STATUS Status;
3719 VARIABLE_STORE_HEADER *VolatileVariableStore;
3720 UINTN ScratchSize;
3721 EFI_GUID *VariableGuid;
3722
3723 //
3724 // Allocate runtime memory for variable driver global structure.
3725 //
3726 mVariableModuleGlobal = AllocateRuntimeZeroPool (sizeof (VARIABLE_MODULE_GLOBAL));
3727 if (mVariableModuleGlobal == NULL) {
3728 return EFI_OUT_OF_RESOURCES;
3729 }
3730
3732
3733 //
3734 // Init non-volatile variable store.
3735 //
3736 Status = InitNonVolatileVariableStore ();
3737 if (EFI_ERROR (Status)) {
3738 FreePool (mVariableModuleGlobal);
3739 return Status;
3740 }
3741
3742 //
3743 // mVariableModuleGlobal->VariableGlobal.AuthFormat
3744 // has been initialized in InitNonVolatileVariableStore().
3745 //
3747 DEBUG ((DEBUG_INFO, "Variable driver will work with auth variable format!\n"));
3748 //
3749 // Set AuthSupport to FALSE first, VariableWriteServiceInitialize() will initialize it.
3750 //
3752 VariableGuid = &gEfiAuthenticatedVariableGuid;
3753 } else {
3754 DEBUG ((DEBUG_INFO, "Variable driver will work without auth variable support!\n"));
3756 VariableGuid = &gEfiVariableGuid;
3757 }
3758
3759 //
3760 // Get HOB variable store.
3761 //
3762 Status = GetHobVariableStore (VariableGuid);
3763 if (EFI_ERROR (Status)) {
3764 if (mNvFvHeaderCache != NULL) {
3765 FreePool (mNvFvHeaderCache);
3766 }
3767
3768 FreePool (mVariableModuleGlobal);
3769 return Status;
3770 }
3771
3772 mVariableModuleGlobal->MaxVolatileVariableSize = ((PcdGet32 (PcdMaxVolatileVariableSize) != 0) ?
3773 PcdGet32 (PcdMaxVolatileVariableSize) :
3775 );
3776 //
3777 // Allocate memory for volatile variable store, note that there is a scratch space to store scratch data.
3778 //
3779 ScratchSize = GetMaxVariableSize ();
3781 VolatileVariableStore = AllocateRuntimePool (PcdGet32 (PcdVariableStoreSize) + ScratchSize);
3782 if (VolatileVariableStore == NULL) {
3784 FreePool ((VOID *)(UINTN)mVariableModuleGlobal->VariableGlobal.HobVariableBase);
3785 }
3786
3787 if (mNvFvHeaderCache != NULL) {
3788 FreePool (mNvFvHeaderCache);
3789 }
3790
3791 FreePool (mVariableModuleGlobal);
3792 return EFI_OUT_OF_RESOURCES;
3793 }
3794
3795 SetMem (VolatileVariableStore, PcdGet32 (PcdVariableStoreSize) + ScratchSize, 0xff);
3796
3797 //
3798 // Initialize Variable Specific Data.
3799 //
3800 mVariableModuleGlobal->VariableGlobal.VolatileVariableBase = (EFI_PHYSICAL_ADDRESS)(UINTN)VolatileVariableStore;
3801 mVariableModuleGlobal->VolatileLastVariableOffset = (UINTN)GetStartPointer (VolatileVariableStore) - (UINTN)VolatileVariableStore;
3802
3803 CopyGuid (&VolatileVariableStore->Signature, VariableGuid);
3804 VolatileVariableStore->Size = PcdGet32 (PcdVariableStoreSize);
3805 VolatileVariableStore->Format = VARIABLE_STORE_FORMATTED;
3806 VolatileVariableStore->State = VARIABLE_STORE_HEALTHY;
3807 VolatileVariableStore->Reserved = 0;
3808 VolatileVariableStore->Reserved1 = 0;
3809
3810 return EFI_SUCCESS;
3811}
3812
3821EFI_STATUS
3823 IN EFI_PHYSICAL_ADDRESS Address,
3824 OUT EFI_HANDLE *FvbHandle OPTIONAL,
3825 OUT EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL **FvbProtocol OPTIONAL
3826 )
3827{
3828 EFI_STATUS Status;
3829 EFI_HANDLE *HandleBuffer;
3830 UINTN HandleCount;
3831 UINTN Index;
3832 EFI_PHYSICAL_ADDRESS FvbBaseAddress;
3833 EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *Fvb;
3834 EFI_FVB_ATTRIBUTES_2 Attributes;
3835 UINTN BlockSize;
3836 UINTN NumberOfBlocks;
3837
3838 HandleBuffer = NULL;
3839 //
3840 // Get all FVB handles.
3841 //
3842 Status = GetFvbCountAndBuffer (&HandleCount, &HandleBuffer);
3843 if (EFI_ERROR (Status)) {
3844 return EFI_NOT_FOUND;
3845 }
3846
3847 //
3848 // Get the FVB to access variable store.
3849 //
3850 Fvb = NULL;
3851 for (Index = 0; Index < HandleCount; Index += 1, Status = EFI_NOT_FOUND, Fvb = NULL) {
3852 Status = GetFvbByHandle (HandleBuffer[Index], &Fvb);
3853 if (EFI_ERROR (Status)) {
3854 Status = EFI_NOT_FOUND;
3855 break;
3856 }
3857
3858 //
3859 // Ensure this FVB protocol supported Write operation.
3860 //
3861 Status = Fvb->GetAttributes (Fvb, &Attributes);
3862 if (EFI_ERROR (Status) || ((Attributes & EFI_FVB2_WRITE_STATUS) == 0)) {
3863 continue;
3864 }
3865
3866 //
3867 // Compare the address and select the right one.
3868 //
3869 Status = Fvb->GetPhysicalAddress (Fvb, &FvbBaseAddress);
3870 if (EFI_ERROR (Status)) {
3871 continue;
3872 }
3873
3874 //
3875 // Assume one FVB has one type of BlockSize.
3876 //
3877 Status = Fvb->GetBlockSize (Fvb, 0, &BlockSize, &NumberOfBlocks);
3878 if (EFI_ERROR (Status)) {
3879 continue;
3880 }
3881
3882 if ((Address >= FvbBaseAddress) && (Address < (FvbBaseAddress + BlockSize * NumberOfBlocks))) {
3883 if (FvbHandle != NULL) {
3884 *FvbHandle = HandleBuffer[Index];
3885 }
3886
3887 if (FvbProtocol != NULL) {
3888 *FvbProtocol = Fvb;
3889 }
3890
3891 Status = EFI_SUCCESS;
3892 break;
3893 }
3894 }
3895
3896 FreePool (HandleBuffer);
3897
3898 if (Fvb == NULL) {
3899 Status = EFI_NOT_FOUND;
3900 }
3901
3902 return Status;
3903}
UINT16 BlockSize
Definition Apm.h:32
UINT16 NumberOfBlocks
Definition Apm.h:21
#define ARRAY_SIZE(Array)
Definition AppleMacEfi.h:34
UINT64 Length
CHAR16 TimeStamp[10]
Definition BiosId.h:49
VOID EFIAPI SecureBootHook(IN CHAR16 *VariableName, IN EFI_GUID *VendorGuid)
DMG_SIZE_DEVICE_PATH Size
OC_TYPING_BUFFER_ENTRY Buffer[OC_TYPING_BUFFER_SIZE]
Definition OcTypingLib.h:42
EFI_STATUS MorLockInit(VOID)
EFI_STATUS SetVariableCheckHandlerMor(IN CHAR16 *VariableName, IN EFI_GUID *VendorGuid, IN UINT32 Attributes, IN UINTN DataSize, IN VOID *Data)
VOID VariableSpeculationBarrier(VOID)
EFI_STATUS FtwVariableSpace(IN EFI_PHYSICAL_ADDRESS VariableBase, IN VARIABLE_STORE_HEADER *VariableBuffer)
Definition Reclaim.c:104
INTN EFIAPI CompareMem(IN CONST VOID *DestinationBuffer, IN CONST VOID *SourceBuffer, IN UINTN Length)
VOID *EFIAPI CopyMem(OUT VOID *DestinationBuffer, IN CONST VOID *SourceBuffer, IN UINTN Length)
VOID *EFIAPI SetMem(OUT VOID *Buffer, IN UINTN Length, IN UINT8 Value)
BOOLEAN EFIAPI CompareGuid(IN CONST GUID *Guid1, IN CONST GUID *Guid2)
GUID *EFIAPI CopyGuid(OUT GUID *DestinationGuid, IN CONST GUID *SourceGuid)
VOID *EFIAPI ZeroMem(OUT VOID *Buffer, IN UINTN Length)
EFI_GUID gEfiGlobalVariableGuid
VOID *EFIAPI GetFirstGuidHob(IN CONST EFI_GUID *Guid)
Definition UserMisc.c:671
EFI_FIRMWARE_VOLUME_HEADER * mNvFvHeaderCache
Definition Variable.c:46
BOOLEAN mEndOfDxe
Definition Variable.c:56
CHAR8 *EFIAPI VariableGetBestLanguage(IN CONST CHAR8 *SupportedLanguages, IN UINTN Iso639Language,...)
Definition Variable.c:1120
VARIABLE_INFO_ENTRY * gVariableInfo
Definition Variable.c:51
BOOLEAN IsUserVariable(IN VARIABLE_HEADER *Variable)
Definition Variable.c:417
AUTH_VAR_LIB_CONTEXT_IN mAuthContextIn
Definition Variable.c:83
UINTN GetMaxVariableSize(VOID)
Definition Variable.c:3268
EFI_STATUS EFIAPI VariableServiceGetVariable(IN CHAR16 *VariableName, IN EFI_GUID *VendorGuid, OUT UINT32 *Attributes OPTIONAL, IN OUT UINTN *DataSize, OUT VOID *Data OPTIONAL)
Definition Variable.c:2435
EFI_STATUS UpdateVariable(IN CHAR16 *VariableName, IN EFI_GUID *VendorGuid, IN VOID *Data, IN UINTN DataSize, IN UINT32 Attributes OPTIONAL, IN UINT32 KeyIndex OPTIONAL, IN UINT64 MonotonicCount OPTIONAL, IN OUT VARIABLE_POINTER_TRACK *CacheVariable, IN EFI_TIME *TimeStamp OPTIONAL)
Definition Variable.c:1680
VOID CalculateCommonUserVariableTotalSize(VOID)
Definition Variable.c:447
AUTH_VAR_LIB_CONTEXT_OUT mAuthContextOut
Definition Variable.c:101
VOID InitializeVariableQuota(VOID)
Definition Variable.c:490
VAR_ERROR_FLAG mCurrentBootVarErrFlag
Definition Variable.c:67
UINTN GetIndexFromSupportedLangCodes(IN CHAR8 *SupportedLang, IN CHAR8 *Lang, IN BOOLEAN Iso639Language)
Definition Variable.c:932
VOID InitializeVarErrorFlag(VOID)
Definition Variable.c:364
EFI_STATUS Reclaim(IN EFI_PHYSICAL_ADDRESS VariableBase, OUT UINTN *LastVariableOffset, IN BOOLEAN IsVolatile, IN OUT VARIABLE_POINTER_TRACK *UpdatingPtrTrack, IN VARIABLE_HEADER *NewVariable, IN UINTN NewVariableSize)
Definition Variable.c:520
CHAR8 * GetLangFromSupportedLangCodes(IN CHAR8 *SupportedLang, IN UINTN Index, IN BOOLEAN Iso639Language)
Definition Variable.c:1019
VOID * ConvertNormalVarStorageToAuthVarStorage(VARIABLE_STORE_HEADER *NormalVarStorage)
Definition Variable.c:3523
EFI_STATUS GetHobVariableStore(IN EFI_GUID *VariableGuid)
Definition Variable.c:3632
BOOLEAN EFIAPI CheckRemainingSpaceForConsistencyInternal(IN UINT32 Attributes, IN VA_LIST Marker)
Definition Variable.c:1242
VARIABLE_STORE_HEADER * mNvVariableCache
Definition Variable.c:41
EFI_STATUS VariableWriteServiceInitialize(VOID)
Definition Variable.c:3426
VOID ReclaimForOS(VOID)
Definition Variable.c:3213
EFI_STATUS VariableCommonInitialize(VOID)
Definition Variable.c:3714
EFI_STATUS EFIAPI VariableServiceGetNextVariableName(IN OUT UINTN *VariableNameSize, IN OUT CHAR16 *VariableName, IN OUT EFI_GUID *VendorGuid)
Definition Variable.c:2525
EFI_STATUS FindVariable(IN CHAR16 *VariableName, IN EFI_GUID *VendorGuid, OUT VARIABLE_POINTER_TRACK *PtrTrack, IN VARIABLE_GLOBAL *Global, IN BOOLEAN IgnoreRtCheck)
Definition Variable.c:853
VAR_CHECK_REQUEST_SOURCE mRequestSource
Definition Variable.c:62
EFI_STATUS EFIAPI VariableServiceQueryVariableInfo(IN UINT32 Attributes, OUT UINT64 *MaximumVariableStorageSize, OUT UINT64 *RemainingVariableStorageSize, OUT UINT64 *MaximumVariableSize)
Definition Variable.c:3131
VARIABLE_ENTRY_PROPERTY mVariableEntryProperty[]
Definition Variable.c:69
EFI_STATUS UpdateVariableStore(IN VARIABLE_GLOBAL *Global, IN BOOLEAN Volatile, IN BOOLEAN SetByIndex, IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *Fvb, IN UINTN DataPtrIndex, IN UINT32 DataSize, IN UINT8 *Buffer)
Definition Variable.c:125
EFI_STATUS AutoUpdateLangVariable(IN CHAR16 *VariableName, IN VOID *Data, IN UINTN DataSize)
Definition Variable.c:1417
EFI_STATUS GetFvbInfoByAddress(IN EFI_PHYSICAL_ADDRESS Address, OUT EFI_HANDLE *FvbHandle OPTIONAL, OUT EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL **FvbProtocol OPTIONAL)
Definition Variable.c:3822
VOID FlushHobVariableToFlash(IN CHAR16 *VariableName, IN EFI_GUID *VendorGuid)
Definition Variable.c:3294
EFI_STATUS EFIAPI VariableServiceQueryVariableInfoInternal(IN UINT32 Attributes, OUT UINT64 *MaximumVariableStorageSize, OUT UINT64 *RemainingVariableStorageSize, OUT UINT64 *MaximumVariableSize)
Definition Variable.c:2951
VARIABLE_MODULE_GLOBAL * mVariableModuleGlobal
Definition Variable.c:35
BOOLEAN EFIAPI CheckRemainingSpaceForConsistency(IN UINT32 Attributes,...)
Definition Variable.c:1379
EFI_STATUS EFIAPI VariableServiceSetVariable(IN CHAR16 *VariableName, IN EFI_GUID *VendorGuid, IN UINT32 Attributes, IN UINTN DataSize, IN VOID *Data)
Definition Variable.c:2627
VOID RecordVarErrorFlag(IN VAR_ERROR_FLAG Flag, IN CHAR16 *VariableName, IN EFI_GUID *VendorGuid, IN UINT32 Attributes, IN UINTN VariableSize)
Definition Variable.c:274
#define EFI_VARIABLE_APPLE_BIT
Definition Variable.c:33
EFI_STATUS GetFvbByHandle(IN EFI_HANDLE FvBlockHandle, OUT EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL **FvBlock)
EFI_LOCK * InitializeLock(IN OUT EFI_LOCK *Lock, IN EFI_TPL Priority)
EFI_STATUS EFIAPI VariableExLibGetScratchBuffer(IN OUT UINTN *ScratchBufferSize, OUT VOID **ScratchBuffer)
BOOLEAN AtRuntime(VOID)
Definition VariableDxe.c:77
#define EFI_VARIABLE_ATTRIBUTES_MASK
Definition Variable.h:48
#define ISO_639_2_ENTRY_SIZE
Definition Variable.h:58
VARIABLE_STORE_TYPE
Definition Variable.h:60
@ VariableStoreTypeNv
Definition Variable.h:63
@ VariableStoreTypeVolatile
Definition Variable.h:61
@ VariableStoreTypeHob
Definition Variable.h:62
@ VariableStoreTypeMax
Definition Variable.h:64
VOID ReleaseLockOnlyAtBootTime(IN EFI_LOCK *Lock)
BOOLEAN EFIAPI VariableExLibAtRuntime(VOID)
BOOLEAN EFIAPI VariableExLibCheckRemainingSpaceForConsistency(IN UINT32 Attributes,...)
VOID AcquireLockOnlyAtBootTime(IN EFI_LOCK *Lock)
EFI_STATUS GetFvbCountAndBuffer(OUT UINTN *NumberHandles, OUT EFI_HANDLE **Buffer)
EFI_STATUS EFIAPI VariableExLibFindVariable(IN CHAR16 *VariableName, IN EFI_GUID *VendorGuid, OUT AUTH_VARIABLE_INFO *AuthVariableInfo)
EFI_STATUS EFIAPI VariableExLibUpdateVariable(IN AUTH_VARIABLE_INFO *AuthVariableInfo)
EFI_STATUS EFIAPI VariableExLibFindNextVariable(IN CHAR16 *VariableName, IN EFI_GUID *VendorGuid, OUT AUTH_VARIABLE_INFO *AuthVariableInfo)
EFI_STATUS InitNonVolatileVariableStore(VOID)
UINTN GetNonVolatileMaxVariableSize(VOID)
EFI_GUID * GetVendorGuidPtr(IN VARIABLE_HEADER *Variable, IN BOOLEAN AuthFormat)
VOID SetDataSizeOfVariable(IN VARIABLE_HEADER *Variable, IN UINTN DataSize, IN BOOLEAN AuthFormat)
VARIABLE_HEADER * GetNextVariablePtr(IN VARIABLE_HEADER *Variable, IN BOOLEAN AuthFormat)
VARIABLE_HEADER * GetStartPointer(IN VARIABLE_STORE_HEADER *VarStoreHeader)
UINT8 * GetVariableDataPtr(IN VARIABLE_HEADER *Variable, IN BOOLEAN AuthFormat)
EFI_STATUS EFIAPI VariableServiceGetNextVariableInternal(IN CHAR16 *VariableName, IN EFI_GUID *VendorGuid, IN VARIABLE_STORE_HEADER **VariableStoreList, OUT VARIABLE_HEADER **VariablePtr, IN BOOLEAN AuthFormat)
VARIABLE_STORE_STATUS GetVariableStoreStatus(IN VARIABLE_STORE_HEADER *VarStoreHeader)
EFI_STATUS FindVariableEx(IN CHAR16 *VariableName, IN EFI_GUID *VendorGuid, IN BOOLEAN IgnoreRtCheck, IN OUT VARIABLE_POINTER_TRACK *PtrTrack, IN BOOLEAN AuthFormat)
UINTN GetVariableDataOffset(IN VARIABLE_HEADER *Variable, IN BOOLEAN AuthFormat)
BOOLEAN IsValidVariableHeader(IN VARIABLE_HEADER *Variable, IN VARIABLE_HEADER *VariableStoreEnd)
UINTN NameSizeOfVariable(IN VARIABLE_HEADER *Variable, IN BOOLEAN AuthFormat)
VARIABLE_HEADER * GetEndPointer(IN VARIABLE_STORE_HEADER *VarStoreHeader)
VOID SetNameSizeOfVariable(IN VARIABLE_HEADER *Variable, IN UINTN NameSize, IN BOOLEAN AuthFormat)
VOID UpdateVariableInfo(IN CHAR16 *VariableName, IN EFI_GUID *VendorGuid, IN BOOLEAN Volatile, IN BOOLEAN Read, IN BOOLEAN Write, IN BOOLEAN Delete, IN BOOLEAN Cache, IN OUT VARIABLE_INFO_ENTRY **VariableInfo)
BOOLEAN VariableCompareTimeStampInternal(IN EFI_TIME *FirstTime, IN EFI_TIME *SecondTime)
UINTN DataSizeOfVariable(IN VARIABLE_HEADER *Variable, IN BOOLEAN AuthFormat)
CHAR16 * GetVariableNamePtr(IN VARIABLE_HEADER *Variable, IN BOOLEAN AuthFormat)
UINTN GetVariableHeaderSize(IN BOOLEAN AuthFormat)
EFI_STATUS SynchronizeRuntimeVariableCache(IN VARIABLE_RUNTIME_CACHE *VariableRuntimeCache, IN UINTN Offset, IN UINTN Length)
#define ASSERT(x)
Definition coder.h:55
#define MIN(a, b)
Definition deflate.c:1673
BOOLEAN AuthFormat
Definition Variable.h:103
EFI_PHYSICAL_ADDRESS VolatileVariableBase
Definition Variable.h:98
VARIABLE_RUNTIME_CACHE_CONTEXT VariableRuntimeCacheContext
Definition Variable.h:100
BOOLEAN EmuNvMode
Definition Variable.h:105
UINT32 ReentrantState
Definition Variable.h:102
EFI_LOCK VariableServicesLock
Definition Variable.h:101
BOOLEAN AuthSupport
Definition Variable.h:104
EFI_PHYSICAL_ADDRESS NonVolatileVariableBase
Definition Variable.h:99
EFI_PHYSICAL_ADDRESS HobVariableBase
Definition Variable.h:97
VARIABLE_GLOBAL VariableGlobal
Definition Variable.h:109
UINTN NonVolatileLastVariableOffset
Definition Variable.h:111
UINTN CommonUserVariableTotalSize
Definition Variable.h:116
CHAR8 Lang[ISO_639_2_ENTRY_SIZE+1]
Definition Variable.h:125
UINTN VolatileLastVariableOffset
Definition Variable.h:110
UINTN CommonMaxUserVariableSpace
Definition Variable.h:113
EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL * FvbInstance
Definition Variable.h:126
UINTN CommonRuntimeVariableSpace
Definition Variable.h:114
VARIABLE_HEADER * CurrPtr
Definition Variable.h:83
VARIABLE_HEADER * EndPtr
Definition Variable.h:91
VARIABLE_HEADER * InDeletedTransitionPtr
Definition Variable.h:90
VARIABLE_HEADER * StartPtr
Definition Variable.h:92
VARIABLE_RUNTIME_CACHE VariableRuntimeVolatileCache
Definition Variable.h:79
VARIABLE_RUNTIME_CACHE VariableRuntimeNvCache
Definition Variable.h:78
VARIABLE_RUNTIME_CACHE VariableRuntimeHobCache
Definition Variable.h:77
VARIABLE_STORE_HEADER * Store
Definition Variable.h:70