8f546bddb3e36f842035f4725bfcbe3ebd242272
[mirror_edk2.git] / MdeModulePkg / Universal / Variable / RuntimeDxe / Variable.c
1 /*++
2
3 Copyright (c) 2006 - 2007, Intel Corporation
4 All rights reserved. This program and the accompanying materials
5 are licensed and made available under the terms and conditions of the BSD License
6 which accompanies this distribution. The full text of the license may be found at
7 http://opensource.org/licenses/bsd-license.php
8
9 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
10 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
11
12 Module Name:
13
14 Variable.c
15
16 Abstract:
17
18 Revision History
19
20 --*/
21
22
23 #include "Variable.h"
24 #include <Guid/FlashMapHob.h>
25
26 //
27 // Don't use module globals after the SetVirtualAddress map is signaled
28 //
29 ESAL_VARIABLE_GLOBAL *mVariableModuleGlobal;
30
31 //
32 // This is a temperary function which will be removed
33 // when EfiAcquireLock in UefiLib can handle the
34 // the call in UEFI Runtimer driver in RT phase.
35 //
36 STATIC
37 VOID
38 AcquireLockOnlyAtBootTime (
39 IN EFI_LOCK *Lock
40 )
41 {
42 if (!EfiAtRuntime ()) {
43 EfiAcquireLock (Lock);
44 }
45 }
46
47 //
48 // This is a temperary function which will be removed
49 // when EfiAcquireLock in UefiLib can handle the
50 // the call in UEFI Runtimer driver in RT phase.
51 //
52 STATIC
53 VOID
54 ReleaseLockOnlyAtBootTime (
55 IN EFI_LOCK *Lock
56 )
57 {
58 if (!EfiAtRuntime ()) {
59 EfiReleaseLock (Lock);
60 }
61 }
62
63 STATIC
64 BOOLEAN
65 EFIAPI
66 IsValidVariableHeader (
67 IN VARIABLE_HEADER *Variable
68 )
69 /*++
70
71 Routine Description:
72
73 This code checks if variable header is valid or not.
74
75 Arguments:
76 Variable Pointer to the Variable Header.
77
78 Returns:
79 TRUE Variable header is valid.
80 FALSE Variable header is not valid.
81
82 --*/
83 {
84 if (Variable == NULL ||
85 Variable->StartId != VARIABLE_DATA ||
86 (sizeof (VARIABLE_HEADER) + Variable->NameSize + Variable->DataSize) > MAX_VARIABLE_SIZE
87 ) {
88 return FALSE;
89 }
90
91 return TRUE;
92 }
93
94 STATIC
95 EFI_STATUS
96 EFIAPI
97 UpdateVariableStore (
98 IN VARIABLE_GLOBAL *Global,
99 IN BOOLEAN Volatile,
100 IN BOOLEAN SetByIndex,
101 IN UINTN Instance,
102 IN UINTN DataPtrIndex,
103 IN UINT32 DataSize,
104 IN UINT8 *Buffer
105 )
106 /*++
107
108 Routine Description:
109
110 This function writes data to the FWH at the correct LBA even if the LBAs
111 are fragmented.
112
113 Arguments:
114
115 Global Pointer to VARAIBLE_GLOBAL structure
116 Volatile If the Variable is Volatile or Non-Volatile
117 SetByIndex TRUE: Target pointer is given as index
118 FALSE: Target pointer is absolute
119 Instance Instance of FV Block services
120 DataPtrIndex Pointer to the Data from the end of VARIABLE_STORE_HEADER
121 structure
122 DataSize Size of data to be written.
123 Buffer Pointer to the buffer from which data is written
124
125 Returns:
126
127 EFI STATUS
128
129 --*/
130 {
131 EFI_FV_BLOCK_MAP_ENTRY *PtrBlockMapEntry;
132 UINTN BlockIndex2;
133 UINTN LinearOffset;
134 UINTN CurrWriteSize;
135 UINTN CurrWritePtr;
136 UINT8 *CurrBuffer;
137 EFI_LBA LbaNumber;
138 UINTN Size;
139 EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader;
140 VARIABLE_STORE_HEADER *VolatileBase;
141 EFI_PHYSICAL_ADDRESS FvVolHdr;
142 EFI_PHYSICAL_ADDRESS DataPtr;
143 EFI_STATUS Status;
144
145 FwVolHeader = NULL;
146 DataPtr = DataPtrIndex;
147
148 //
149 // Check if the Data is Volatile
150 //
151 if (!Volatile) {
152 EfiFvbGetPhysicalAddress (Instance, &FvVolHdr);
153 FwVolHeader = (EFI_FIRMWARE_VOLUME_HEADER *) ((UINTN) FvVolHdr);
154 //
155 // Data Pointer should point to the actual Address where data is to be
156 // written
157 //
158 if (SetByIndex) {
159 DataPtr += Global->NonVolatileVariableBase;
160 }
161
162 if ((DataPtr + DataSize) >= ((EFI_PHYSICAL_ADDRESS) (UINTN) ((UINT8 *) FwVolHeader + FwVolHeader->FvLength))) {
163 return EFI_INVALID_PARAMETER;
164 }
165 } else {
166 //
167 // Data Pointer should point to the actual Address where data is to be
168 // written
169 //
170 VolatileBase = (VARIABLE_STORE_HEADER *) ((UINTN) Global->VolatileVariableBase);
171 if (SetByIndex) {
172 DataPtr += Global->VolatileVariableBase;
173 }
174
175 if ((DataPtr + DataSize) >= ((UINTN) ((UINT8 *) VolatileBase + VolatileBase->Size))) {
176 return EFI_INVALID_PARAMETER;
177 }
178 }
179 //
180 // If Volatile Variable just do a simple mem copy.
181 //
182 if (Volatile) {
183 CopyMem ((UINT8 *) ((UINTN) DataPtr), Buffer, DataSize);
184 return EFI_SUCCESS;
185 }
186 //
187 // If we are here we are dealing with Non-Volatile Variables
188 //
189 LinearOffset = (UINTN) FwVolHeader;
190 CurrWritePtr = (UINTN) DataPtr;
191 CurrWriteSize = DataSize;
192 CurrBuffer = Buffer;
193 LbaNumber = 0;
194
195 if (CurrWritePtr < LinearOffset) {
196 return EFI_INVALID_PARAMETER;
197 }
198
199 for (PtrBlockMapEntry = FwVolHeader->BlockMap; PtrBlockMapEntry->NumBlocks != 0; PtrBlockMapEntry++) {
200 for (BlockIndex2 = 0; BlockIndex2 < PtrBlockMapEntry->NumBlocks; BlockIndex2++) {
201 //
202 // Check to see if the Variable Writes are spanning through multiple
203 // blocks.
204 //
205 if ((CurrWritePtr >= LinearOffset) && (CurrWritePtr < LinearOffset + PtrBlockMapEntry->Length)) {
206 if ((CurrWritePtr + CurrWriteSize) <= (LinearOffset + PtrBlockMapEntry->Length)) {
207 Status = EfiFvbWriteBlock (
208 Instance,
209 LbaNumber,
210 (UINTN) (CurrWritePtr - LinearOffset),
211 &CurrWriteSize,
212 CurrBuffer
213 );
214 if (EFI_ERROR (Status)) {
215 return Status;
216 }
217 } else {
218 Size = (UINT32) (LinearOffset + PtrBlockMapEntry->Length - CurrWritePtr);
219 Status = EfiFvbWriteBlock (
220 Instance,
221 LbaNumber,
222 (UINTN) (CurrWritePtr - LinearOffset),
223 &Size,
224 CurrBuffer
225 );
226 if (EFI_ERROR (Status)) {
227 return Status;
228 }
229
230 CurrWritePtr = LinearOffset + PtrBlockMapEntry->Length;
231 CurrBuffer = CurrBuffer + Size;
232 CurrWriteSize = CurrWriteSize - Size;
233 }
234 }
235
236 LinearOffset += PtrBlockMapEntry->Length;
237 LbaNumber++;
238 }
239 }
240
241 return EFI_SUCCESS;
242 }
243
244 STATIC
245 VARIABLE_STORE_STATUS
246 EFIAPI
247 GetVariableStoreStatus (
248 IN VARIABLE_STORE_HEADER *VarStoreHeader
249 )
250 /*++
251
252 Routine Description:
253
254 This code gets the current status of Variable Store.
255
256 Arguments:
257
258 VarStoreHeader Pointer to the Variable Store Header.
259
260 Returns:
261
262 EfiRaw Variable store status is raw
263 EfiValid Variable store status is valid
264 EfiInvalid Variable store status is invalid
265
266 --*/
267 {
268 if (VarStoreHeader->Signature == VARIABLE_STORE_SIGNATURE &&
269 VarStoreHeader->Format == VARIABLE_STORE_FORMATTED &&
270 VarStoreHeader->State == VARIABLE_STORE_HEALTHY
271 ) {
272
273 return EfiValid;
274 } else if (VarStoreHeader->Signature == 0xffffffff &&
275 VarStoreHeader->Size == 0xffffffff &&
276 VarStoreHeader->Format == 0xff &&
277 VarStoreHeader->State == 0xff
278 ) {
279
280 return EfiRaw;
281 } else {
282 return EfiInvalid;
283 }
284 }
285
286 STATIC
287 UINT8 *
288 EFIAPI
289 GetVariableDataPtr (
290 IN VARIABLE_HEADER *Variable
291 )
292 /*++
293
294 Routine Description:
295
296 This code gets the pointer to the variable data.
297
298 Arguments:
299
300 Variable Pointer to the Variable Header.
301
302 Returns:
303
304 UINT8* Pointer to Variable Data
305
306 --*/
307 {
308 //
309 // Be careful about pad size for alignment
310 //
311 return (UINT8 *) ((UINTN) GET_VARIABLE_NAME_PTR (Variable) + Variable->NameSize + GET_PAD_SIZE (Variable->NameSize));
312 }
313
314 STATIC
315 VARIABLE_HEADER *
316 EFIAPI
317 GetNextVariablePtr (
318 IN VARIABLE_HEADER *Variable
319 )
320 /*++
321
322 Routine Description:
323
324 This code gets the pointer to the next variable header.
325
326 Arguments:
327
328 Variable Pointer to the Variable Header.
329
330 Returns:
331
332 VARIABLE_HEADER* Pointer to next variable header.
333
334 --*/
335 {
336 if (!IsValidVariableHeader (Variable)) {
337 return NULL;
338 }
339 //
340 // Be careful about pad size for alignment
341 //
342 return (VARIABLE_HEADER *) ((UINTN) GetVariableDataPtr (Variable) + Variable->DataSize + GET_PAD_SIZE (Variable->DataSize));
343 }
344
345 STATIC
346 VARIABLE_HEADER *
347 EFIAPI
348 GetEndPointer (
349 IN VARIABLE_STORE_HEADER *VarStoreHeader
350 )
351 /*++
352
353 Routine Description:
354
355 This code gets the pointer to the last variable memory pointer byte
356
357 Arguments:
358
359 VarStoreHeader Pointer to the Variable Store Header.
360
361 Returns:
362
363 VARIABLE_HEADER* Pointer to last unavailable Variable Header
364
365 --*/
366 {
367 //
368 // The end of variable store
369 //
370 return (VARIABLE_HEADER *) ((UINTN) VarStoreHeader + VarStoreHeader->Size);
371 }
372
373 STATIC
374 EFI_STATUS
375 EFIAPI
376 Reclaim (
377 IN EFI_PHYSICAL_ADDRESS VariableBase,
378 OUT UINTN *LastVariableOffset,
379 IN BOOLEAN IsVolatile
380 )
381 /*++
382
383 Routine Description:
384
385 Variable store garbage collection and reclaim operation
386
387 Arguments:
388
389 VariableBase Base address of variable store
390 LastVariableOffset Offset of last variable
391 IsVolatile The variable store is volatile or not,
392 if it is non-volatile, need FTW
393
394 Returns:
395
396 EFI STATUS
397
398 --*/
399 {
400 VARIABLE_HEADER *Variable;
401 VARIABLE_HEADER *NextVariable;
402 VARIABLE_STORE_HEADER *VariableStoreHeader;
403 UINT8 *ValidBuffer;
404 UINTN ValidBufferSize;
405 UINTN VariableSize;
406 UINT8 *CurrPtr;
407 EFI_STATUS Status;
408
409 VariableStoreHeader = (VARIABLE_STORE_HEADER *) ((UINTN) VariableBase);
410
411 //
412 // Start Pointers for the variable.
413 //
414 Variable = (VARIABLE_HEADER *) (VariableStoreHeader + 1);
415
416 ValidBufferSize = sizeof (VARIABLE_STORE_HEADER);
417
418 while (IsValidVariableHeader (Variable)) {
419 NextVariable = GetNextVariablePtr (Variable);
420 if (Variable->State == VAR_ADDED) {
421 VariableSize = (UINTN) NextVariable - (UINTN) Variable;
422 ValidBufferSize += VariableSize;
423 }
424
425 Variable = NextVariable;
426 }
427
428 ValidBuffer = AllocatePool (ValidBufferSize);
429 if (ValidBuffer == NULL) {
430 return EFI_OUT_OF_RESOURCES;
431 }
432
433 SetMem (ValidBuffer, ValidBufferSize, 0xff);
434
435 CurrPtr = ValidBuffer;
436
437 //
438 // Copy variable store header
439 //
440 CopyMem (CurrPtr, VariableStoreHeader, sizeof (VARIABLE_STORE_HEADER));
441 CurrPtr += sizeof (VARIABLE_STORE_HEADER);
442
443 //
444 // Start Pointers for the variable.
445 //
446 Variable = (VARIABLE_HEADER *) (VariableStoreHeader + 1);
447
448 while (IsValidVariableHeader (Variable)) {
449 NextVariable = GetNextVariablePtr (Variable);
450 if (Variable->State == VAR_ADDED) {
451 VariableSize = (UINTN) NextVariable - (UINTN) Variable;
452 CopyMem (CurrPtr, (UINT8 *) Variable, VariableSize);
453 CurrPtr += VariableSize;
454 }
455
456 Variable = NextVariable;
457 }
458
459 if (IsVolatile) {
460 //
461 // If volatile variable store, just copy valid buffer
462 //
463 SetMem ((UINT8 *) (UINTN) VariableBase, VariableStoreHeader->Size, 0xff);
464 CopyMem ((UINT8 *) (UINTN) VariableBase, ValidBuffer, ValidBufferSize);
465 *LastVariableOffset = ValidBufferSize;
466 Status = EFI_SUCCESS;
467 } else {
468 //
469 // If non-volatile variable store, perform FTW here.
470 //
471 Status = FtwVariableSpace (
472 VariableBase,
473 ValidBuffer,
474 ValidBufferSize
475 );
476 if (!EFI_ERROR (Status)) {
477 *LastVariableOffset = ValidBufferSize;
478 }
479 }
480
481 FreePool (ValidBuffer);
482
483 if (EFI_ERROR (Status)) {
484 *LastVariableOffset = 0;
485 }
486
487 return Status;
488 }
489
490 STATIC
491 EFI_STATUS
492 EFIAPI
493 FindVariable (
494 IN CHAR16 *VariableName,
495 IN EFI_GUID *VendorGuid,
496 OUT VARIABLE_POINTER_TRACK *PtrTrack,
497 IN VARIABLE_GLOBAL *Global
498 )
499 /*++
500
501 Routine Description:
502
503 This code finds variable in storage blocks (Volatile or Non-Volatile)
504
505 Arguments:
506
507 VariableName Name of the variable to be found
508 VendorGuid Vendor GUID to be found.
509 PtrTrack Variable Track Pointer structure that contains
510 Variable Information.
511 Contains the pointer of Variable header.
512 Global VARIABLE_GLOBAL pointer
513
514 Returns:
515
516 EFI STATUS
517
518 --*/
519 {
520 VARIABLE_HEADER *Variable[2];
521 VARIABLE_STORE_HEADER *VariableStoreHeader[2];
522 UINTN Index;
523
524 //
525 // We aquire the lock at the entry of FindVariable as GetVariable, GetNextVariableName
526 // SetVariable all call FindVariable at entry point. Please move "Aquire Lock" to
527 // the correct places if this assumption does not hold TRUE anymore.
528 //
529 AcquireLockOnlyAtBootTime(&Global->VariableServicesLock);
530
531 //
532 // 0: Non-Volatile, 1: Volatile
533 //
534 VariableStoreHeader[0] = (VARIABLE_STORE_HEADER *) ((UINTN) Global->NonVolatileVariableBase);
535 VariableStoreHeader[1] = (VARIABLE_STORE_HEADER *) ((UINTN) Global->VolatileVariableBase);
536
537 //
538 // Start Pointers for the variable.
539 // Actual Data Pointer where data can be written.
540 //
541 Variable[0] = (VARIABLE_HEADER *) (VariableStoreHeader[0] + 1);
542 Variable[1] = (VARIABLE_HEADER *) (VariableStoreHeader[1] + 1);
543
544 if (VariableName[0] != 0 && VendorGuid == NULL) {
545 return EFI_INVALID_PARAMETER;
546 }
547 //
548 // Find the variable by walk through non-volatile and volatile variable store
549 //
550 for (Index = 0; Index < 2; Index++) {
551 PtrTrack->StartPtr = (VARIABLE_HEADER *) (VariableStoreHeader[Index] + 1);
552 PtrTrack->EndPtr = GetEndPointer (VariableStoreHeader[Index]);
553
554 while (IsValidVariableHeader (Variable[Index]) && (Variable[Index] <= GetEndPointer (VariableStoreHeader[Index]))) {
555 if (Variable[Index]->State == VAR_ADDED) {
556 if (!(EfiAtRuntime () && !(Variable[Index]->Attributes & EFI_VARIABLE_RUNTIME_ACCESS))) {
557 if (VariableName[0] == 0) {
558 PtrTrack->CurrPtr = Variable[Index];
559 PtrTrack->Volatile = (BOOLEAN) Index;
560 return EFI_SUCCESS;
561 } else {
562 if (CompareGuid (VendorGuid, &Variable[Index]->VendorGuid)) {
563 if (!CompareMem (VariableName, GET_VARIABLE_NAME_PTR (Variable[Index]), Variable[Index]->NameSize)) {
564 PtrTrack->CurrPtr = Variable[Index];
565 PtrTrack->Volatile = (BOOLEAN) Index;
566 return EFI_SUCCESS;
567 }
568 }
569 }
570 }
571 }
572
573 Variable[Index] = GetNextVariablePtr (Variable[Index]);
574 }
575 //
576 // While (...)
577 //
578 }
579 //
580 // for (...)
581 //
582 PtrTrack->CurrPtr = NULL;
583 return EFI_NOT_FOUND;
584 }
585
586 EFI_STATUS
587 EFIAPI
588 GetVariable (
589 IN CHAR16 *VariableName,
590 IN EFI_GUID * VendorGuid,
591 OUT UINT32 *Attributes OPTIONAL,
592 IN OUT UINTN *DataSize,
593 OUT VOID *Data,
594 IN VARIABLE_GLOBAL * Global,
595 IN UINT32 Instance
596 )
597 /*++
598
599 Routine Description:
600
601 This code finds variable in storage blocks (Volatile or Non-Volatile)
602
603 Arguments:
604
605 VariableName Name of Variable to be found
606 VendorGuid Variable vendor GUID
607 Attributes OPTIONAL Attribute value of the variable found
608 DataSize Size of Data found. If size is less than the
609 data, this value contains the required size.
610 Data Data pointer
611 Global Pointer to VARIABLE_GLOBAL structure
612 Instance Instance of the Firmware Volume.
613
614 Returns:
615
616 EFI STATUS
617
618 --*/
619 {
620 VARIABLE_POINTER_TRACK Variable;
621 UINTN VarDataSize;
622 EFI_STATUS Status;
623
624 if (VariableName == NULL || VendorGuid == NULL || DataSize == NULL) {
625 return EFI_INVALID_PARAMETER;
626 }
627 //
628 // Find existing variable
629 //
630 Status = FindVariable (VariableName, VendorGuid, &Variable, Global);
631
632 if (Variable.CurrPtr == NULL || EFI_ERROR (Status)) {
633 goto Done;
634 }
635 //
636 // Get data size
637 //
638 VarDataSize = Variable.CurrPtr->DataSize;
639 if (*DataSize >= VarDataSize) {
640 if (Data == NULL) {
641 Status = EFI_INVALID_PARAMETER;
642 goto Done;
643 }
644
645 CopyMem (Data, GetVariableDataPtr (Variable.CurrPtr), VarDataSize);
646 if (Attributes != NULL) {
647 *Attributes = Variable.CurrPtr->Attributes;
648 }
649
650 *DataSize = VarDataSize;
651 Status = EFI_SUCCESS;
652 goto Done;
653 } else {
654 *DataSize = VarDataSize;
655 Status = EFI_BUFFER_TOO_SMALL;
656 goto Done;
657 }
658
659 Done:
660 ReleaseLockOnlyAtBootTime (&Global->VariableServicesLock);
661 return Status;
662 }
663
664 EFI_STATUS
665 EFIAPI
666 GetNextVariableName (
667 IN OUT UINTN *VariableNameSize,
668 IN OUT CHAR16 *VariableName,
669 IN OUT EFI_GUID *VendorGuid,
670 IN VARIABLE_GLOBAL *Global,
671 IN UINT32 Instance
672 )
673 /*++
674
675 Routine Description:
676
677 This code Finds the Next available variable
678
679 Arguments:
680
681 VariableNameSize Size of the variable
682 VariableName Pointer to variable name
683 VendorGuid Variable Vendor Guid
684 Global VARIABLE_GLOBAL structure pointer.
685 Instance FV instance
686
687 Returns:
688
689 EFI STATUS
690
691 --*/
692 {
693 VARIABLE_POINTER_TRACK Variable;
694 UINTN VarNameSize;
695 EFI_STATUS Status;
696
697 if (VariableNameSize == NULL || VariableName == NULL || VendorGuid == NULL) {
698 return EFI_INVALID_PARAMETER;
699 }
700
701 Status = FindVariable (VariableName, VendorGuid, &Variable, Global);
702
703 if (Variable.CurrPtr == NULL || EFI_ERROR (Status)) {
704 goto Done;
705 }
706
707 if (VariableName[0] != 0) {
708 //
709 // If variable name is not NULL, get next variable
710 //
711 Variable.CurrPtr = GetNextVariablePtr (Variable.CurrPtr);
712 }
713
714 while (TRUE) {
715 //
716 // If both volatile and non-volatile variable store are parsed,
717 // return not found
718 //
719 if (Variable.CurrPtr >= Variable.EndPtr || Variable.CurrPtr == NULL) {
720 Variable.Volatile = (BOOLEAN) (Variable.Volatile ^ ((BOOLEAN) 0x1));
721 if (Variable.Volatile) {
722 Variable.StartPtr = (VARIABLE_HEADER *) ((UINTN) (Global->VolatileVariableBase + sizeof (VARIABLE_STORE_HEADER)));
723 Variable.EndPtr = (VARIABLE_HEADER *) GetEndPointer ((VARIABLE_STORE_HEADER *) ((UINTN) Global->VolatileVariableBase));
724 } else {
725 Status = EFI_NOT_FOUND;
726 goto Done;
727 }
728
729 Variable.CurrPtr = Variable.StartPtr;
730 if (!IsValidVariableHeader (Variable.CurrPtr)) {
731 continue;
732 }
733 }
734 //
735 // Variable is found
736 //
737 if (IsValidVariableHeader (Variable.CurrPtr) && Variable.CurrPtr->State == VAR_ADDED) {
738 if (!(EfiAtRuntime () && !(Variable.CurrPtr->Attributes & EFI_VARIABLE_RUNTIME_ACCESS))) {
739 VarNameSize = Variable.CurrPtr->NameSize;
740 if (VarNameSize <= *VariableNameSize) {
741 CopyMem (
742 VariableName,
743 GET_VARIABLE_NAME_PTR (Variable.CurrPtr),
744 VarNameSize
745 );
746 CopyMem (
747 VendorGuid,
748 &Variable.CurrPtr->VendorGuid,
749 sizeof (EFI_GUID)
750 );
751 Status = EFI_SUCCESS;
752 } else {
753 Status = EFI_BUFFER_TOO_SMALL;
754 }
755
756 *VariableNameSize = VarNameSize;
757 goto Done;
758 }
759 }
760
761 Variable.CurrPtr = GetNextVariablePtr (Variable.CurrPtr);
762 }
763
764 Done:
765 ReleaseLockOnlyAtBootTime (&Global->VariableServicesLock);
766 return Status;
767 }
768
769 EFI_STATUS
770 EFIAPI
771 SetVariable (
772 IN CHAR16 *VariableName,
773 IN EFI_GUID *VendorGuid,
774 IN UINT32 Attributes,
775 IN UINTN DataSize,
776 IN VOID *Data,
777 IN VARIABLE_GLOBAL *Global,
778 IN UINTN *VolatileOffset,
779 IN UINTN *NonVolatileOffset,
780 IN UINT32 Instance
781 )
782 /*++
783
784 Routine Description:
785
786 This code sets variable in storage blocks (Volatile or Non-Volatile)
787
788 Arguments:
789
790 VariableName Name of Variable to be found
791 VendorGuid Variable vendor GUID
792 Attributes Attribute value of the variable found
793 DataSize Size of Data found. If size is less than the
794 data, this value contains the required size.
795 Data Data pointer
796 Global Pointer to VARIABLE_GLOBAL structure
797 VolatileOffset The offset of last volatile variable
798 NonVolatileOffset The offset of last non-volatile variable
799 Instance Instance of the Firmware Volume.
800
801 Returns:
802
803 EFI STATUS
804 EFI_INVALID_PARAMETER - Invalid parameter
805 EFI_SUCCESS - Set successfully
806 EFI_OUT_OF_RESOURCES - Resource not enough to set variable
807 EFI_NOT_FOUND - Not found
808
809 --*/
810 {
811 VARIABLE_POINTER_TRACK Variable;
812 EFI_STATUS Status;
813 VARIABLE_HEADER *NextVariable;
814 UINTN VarNameSize;
815 UINTN VarNameOffset;
816 UINTN VarDataOffset;
817 UINTN VarSize;
818 UINT8 State;
819 BOOLEAN Reclaimed;
820
821 Reclaimed = FALSE;
822
823 if (VariableName == NULL || VariableName[0] == 0 || VendorGuid == NULL) {
824 return EFI_INVALID_PARAMETER;
825 }
826
827 Status = FindVariable (VariableName, VendorGuid, &Variable, Global);
828
829 if (Status == EFI_INVALID_PARAMETER) {
830 goto Done;
831 } else if (!EFI_ERROR (Status) && Variable.Volatile && EfiAtRuntime()) {
832 //
833 // If EfiAtRuntime and the variable is Volatile and Runtime Access,
834 // the volatile is ReadOnly, and SetVariable should be aborted and
835 // return EFI_WRITE_PROTECTED.
836 //
837 Status = EFI_WRITE_PROTECTED;
838 goto Done;
839 } else if (sizeof (VARIABLE_HEADER) + StrSize (VariableName) + DataSize > MAX_VARIABLE_SIZE) {
840 //
841 // The size of the VariableName, including the Unicode Null in bytes plus
842 // the DataSize is limited to maximum size of MAX_VARIABLE_SIZE (1024) bytes.
843 //
844 Status = EFI_INVALID_PARAMETER;
845 goto Done;
846 } else if (Attributes == EFI_VARIABLE_NON_VOLATILE) {
847 //
848 // Make sure not only EFI_VARIABLE_NON_VOLATILE is set
849 //
850 Status = EFI_INVALID_PARAMETER;
851 goto Done;
852 } else if ((Attributes & (EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS)) ==
853 EFI_VARIABLE_RUNTIME_ACCESS) {
854 //
855 // Make sure if runtime bit is set, boot service bit is set also
856 //
857 Status = EFI_INVALID_PARAMETER;
858 goto Done;
859 } else if (EfiAtRuntime () && Attributes && !(Attributes & EFI_VARIABLE_RUNTIME_ACCESS)) {
860 //
861 // Runtime but Attribute is not Runtime
862 //
863 Status = EFI_INVALID_PARAMETER;
864 goto Done;
865 } else if (EfiAtRuntime () && Attributes && !(Attributes & EFI_VARIABLE_NON_VOLATILE)) {
866 //
867 // Cannot set volatile variable in Runtime
868 //
869 Status = EFI_INVALID_PARAMETER;
870 goto Done;
871 } else if (DataSize == 0 || (Attributes & (EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS)) == 0) {
872 //
873 // Setting a data variable with no access, or zero DataSize attributes
874 // specified causes it to be deleted.
875 //
876 if (!EFI_ERROR (Status)) {
877 State = Variable.CurrPtr->State;
878 State &= VAR_DELETED;
879
880 Status = UpdateVariableStore (
881 Global,
882 Variable.Volatile,
883 FALSE,
884 Instance,
885 (UINTN) &Variable.CurrPtr->State,
886 sizeof (UINT8),
887 &State
888 );
889 if (EFI_ERROR (Status)) {
890 goto Done;
891 }
892
893 Status = EFI_SUCCESS;
894 goto Done;
895 }
896
897 Status = EFI_NOT_FOUND;
898 goto Done;
899 } else {
900 if (!EFI_ERROR (Status)) {
901 //
902 // If the variable is marked valid and the same data has been passed in
903 // then return to the caller immediately.
904 //
905 if (Variable.CurrPtr->DataSize == DataSize &&
906 !CompareMem (Data, GetVariableDataPtr (Variable.CurrPtr), DataSize)
907 ) {
908 Status = EFI_SUCCESS;
909 goto Done;
910 } else if (Variable.CurrPtr->State == VAR_ADDED) {
911 //
912 // Mark the old variable as in delete transition
913 //
914 State = Variable.CurrPtr->State;
915 State &= VAR_IN_DELETED_TRANSITION;
916
917 Status = UpdateVariableStore (
918 Global,
919 Variable.Volatile,
920 FALSE,
921 Instance,
922 (UINTN) &Variable.CurrPtr->State,
923 sizeof (UINT8),
924 &State
925 );
926 if (EFI_ERROR (Status)) {
927 goto Done;
928 }
929 }
930 }
931 //
932 // Create a new variable and copy the data.
933 //
934 // Tricky part: Use scratch data area at the end of volatile variable store
935 // as a temporary storage.
936 //
937 NextVariable = GetEndPointer ((VARIABLE_STORE_HEADER *) ((UINTN) Global->VolatileVariableBase));
938
939 SetMem (NextVariable, SCRATCH_SIZE, 0xff);
940
941 NextVariable->StartId = VARIABLE_DATA;
942 NextVariable->Attributes = Attributes;
943 //
944 // NextVariable->State = VAR_ADDED;
945 //
946 NextVariable->Reserved = 0;
947 VarNameOffset = sizeof (VARIABLE_HEADER);
948 VarNameSize = StrSize (VariableName);
949 CopyMem (
950 (UINT8 *) ((UINTN) NextVariable + VarNameOffset),
951 VariableName,
952 VarNameSize
953 );
954 VarDataOffset = VarNameOffset + VarNameSize + GET_PAD_SIZE (VarNameSize);
955 CopyMem (
956 (UINT8 *) ((UINTN) NextVariable + VarDataOffset),
957 Data,
958 DataSize
959 );
960 CopyMem (&NextVariable->VendorGuid, VendorGuid, sizeof (EFI_GUID));
961 //
962 // There will be pad bytes after Data, the NextVariable->NameSize and
963 // NextVariable->DataSize should not include pad size so that variable
964 // service can get actual size in GetVariable
965 //
966 NextVariable->NameSize = (UINT32)VarNameSize;
967 NextVariable->DataSize = (UINT32)DataSize;
968
969 //
970 // The actual size of the variable that stores in storage should
971 // include pad size.
972 //
973 VarSize = VarDataOffset + DataSize + GET_PAD_SIZE (DataSize);
974 if (Attributes & EFI_VARIABLE_NON_VOLATILE) {
975 if ((UINT32) (VarSize +*NonVolatileOffset) >
976 ((VARIABLE_STORE_HEADER *) ((UINTN) (Global->NonVolatileVariableBase)))->Size
977 ) {
978 if (EfiAtRuntime ()) {
979 Status = EFI_OUT_OF_RESOURCES;
980 goto Done;
981 }
982 //
983 // Perform garbage collection & reclaim operation
984 //
985 Status = Reclaim (Global->NonVolatileVariableBase, NonVolatileOffset, FALSE);
986 if (EFI_ERROR (Status)) {
987 goto Done;
988 }
989 //
990 // If still no enough space, return out of resources
991 //
992 if ((UINT32) (VarSize +*NonVolatileOffset) >
993 ((VARIABLE_STORE_HEADER *) ((UINTN) (Global->NonVolatileVariableBase)))->Size
994 ) {
995 Status = EFI_OUT_OF_RESOURCES;
996 goto Done;
997 }
998
999 Reclaimed = TRUE;
1000 }
1001 //
1002 // Three steps
1003 // 1. Write variable header
1004 // 2. Write variable data
1005 // 3. Set variable state to valid
1006 //
1007 //
1008 // Step 1:
1009 //
1010 Status = UpdateVariableStore (
1011 Global,
1012 FALSE,
1013 TRUE,
1014 Instance,
1015 *NonVolatileOffset,
1016 sizeof (VARIABLE_HEADER),
1017 (UINT8 *) NextVariable
1018 );
1019
1020 if (EFI_ERROR (Status)) {
1021 goto Done;
1022 }
1023 //
1024 // Step 2:
1025 //
1026 Status = UpdateVariableStore (
1027 Global,
1028 FALSE,
1029 TRUE,
1030 Instance,
1031 *NonVolatileOffset + sizeof (VARIABLE_HEADER),
1032 (UINT32) VarSize - sizeof (VARIABLE_HEADER),
1033 (UINT8 *) NextVariable + sizeof (VARIABLE_HEADER)
1034 );
1035
1036 if (EFI_ERROR (Status)) {
1037 goto Done;
1038 }
1039 //
1040 // Step 3:
1041 //
1042 NextVariable->State = VAR_ADDED;
1043 Status = UpdateVariableStore (
1044 Global,
1045 FALSE,
1046 TRUE,
1047 Instance,
1048 *NonVolatileOffset,
1049 sizeof (VARIABLE_HEADER),
1050 (UINT8 *) NextVariable
1051 );
1052
1053 if (EFI_ERROR (Status)) {
1054 goto Done;
1055 }
1056
1057 *NonVolatileOffset = *NonVolatileOffset + VarSize;
1058
1059 } else {
1060 if (EfiAtRuntime ()) {
1061 Status = EFI_INVALID_PARAMETER;
1062 goto Done;
1063 }
1064
1065 if ((UINT32) (VarSize +*VolatileOffset) >
1066 ((VARIABLE_STORE_HEADER *) ((UINTN) (Global->VolatileVariableBase)))->Size
1067 ) {
1068 //
1069 // Perform garbage collection & reclaim operation
1070 //
1071 Status = Reclaim (Global->VolatileVariableBase, VolatileOffset, TRUE);
1072 if (EFI_ERROR (Status)) {
1073 goto Done;
1074 }
1075 //
1076 // If still no enough space, return out of resources
1077 //
1078 if ((UINT32) (VarSize +*VolatileOffset) >
1079 ((VARIABLE_STORE_HEADER *) ((UINTN) (Global->VolatileVariableBase)))->Size
1080 ) {
1081 Status = EFI_OUT_OF_RESOURCES;
1082 goto Done;
1083 }
1084
1085 Reclaimed = TRUE;
1086 }
1087
1088 NextVariable->State = VAR_ADDED;
1089 Status = UpdateVariableStore (
1090 Global,
1091 TRUE,
1092 TRUE,
1093 Instance,
1094 *VolatileOffset,
1095 (UINT32) VarSize,
1096 (UINT8 *) NextVariable
1097 );
1098
1099 if (EFI_ERROR (Status)) {
1100 goto Done;
1101 }
1102
1103 *VolatileOffset = *VolatileOffset + VarSize;
1104 }
1105 //
1106 // Mark the old variable as deleted
1107 //
1108 if (!Reclaimed && !EFI_ERROR (Status) && Variable.CurrPtr != NULL) {
1109 State = Variable.CurrPtr->State;
1110 State &= VAR_DELETED;
1111
1112 Status = UpdateVariableStore (
1113 Global,
1114 Variable.Volatile,
1115 FALSE,
1116 Instance,
1117 (UINTN) &Variable.CurrPtr->State,
1118 sizeof (UINT8),
1119 &State
1120 );
1121
1122 if (EFI_ERROR (Status)) {
1123 goto Done;
1124 }
1125 }
1126 }
1127
1128 Status = EFI_SUCCESS;
1129 Done:
1130 ReleaseLockOnlyAtBootTime (&Global->VariableServicesLock);
1131 return Status;
1132 }
1133
1134 EFI_STATUS
1135 EFIAPI
1136 QueryVariableInfo (
1137 IN UINT32 Attributes,
1138 OUT UINT64 *MaximumVariableStorageSize,
1139 OUT UINT64 *RemainingVariableStorageSize,
1140 OUT UINT64 *MaximumVariableSize,
1141 IN VARIABLE_GLOBAL *Global,
1142 IN UINT32 Instance
1143 )
1144 /*++
1145
1146 Routine Description:
1147
1148 This code returns information about the EFI variables.
1149
1150 Arguments:
1151
1152 Attributes Attributes bitmask to specify the type of variables
1153 on which to return information.
1154 MaximumVariableStorageSize Pointer to the maximum size of the storage space available
1155 for the EFI variables associated with the attributes specified.
1156 RemainingVariableStorageSize Pointer to the remaining size of the storage space available
1157 for the EFI variables associated with the attributes specified.
1158 MaximumVariableSize Pointer to the maximum size of the individual EFI variables
1159 associated with the attributes specified.
1160 Global Pointer to VARIABLE_GLOBAL structure.
1161 Instance Instance of the Firmware Volume.
1162
1163 Returns:
1164
1165 EFI STATUS
1166 EFI_INVALID_PARAMETER - An invalid combination of attribute bits was supplied.
1167 EFI_SUCCESS - Query successfully.
1168 EFI_UNSUPPORTED - The attribute is not supported on this platform.
1169
1170 --*/
1171 {
1172 VARIABLE_HEADER *Variable;
1173 VARIABLE_HEADER *NextVariable;
1174 UINT64 VariableSize;
1175 VARIABLE_STORE_HEADER *VariableStoreHeader;
1176
1177 if(MaximumVariableStorageSize == NULL || RemainingVariableStorageSize == NULL || MaximumVariableSize == NULL) {
1178 return EFI_INVALID_PARAMETER;
1179 }
1180
1181 if((Attributes & (EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS)) == 0) {
1182 //
1183 // Make sure the Attributes combination is supported by the platform.
1184 //
1185 return EFI_UNSUPPORTED;
1186 } else if ((Attributes & (EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS)) == EFI_VARIABLE_RUNTIME_ACCESS) {
1187 //
1188 // Make sure if runtime bit is set, boot service bit is set also.
1189 //
1190 return EFI_INVALID_PARAMETER;
1191 } else if (EfiAtRuntime () && !(Attributes & EFI_VARIABLE_RUNTIME_ACCESS)) {
1192 //
1193 // Make sure RT Attribute is set if we are in Runtime phase.
1194 //
1195 return EFI_INVALID_PARAMETER;
1196 }
1197
1198 AcquireLockOnlyAtBootTime(&Global->VariableServicesLock);
1199
1200 if((Attributes & EFI_VARIABLE_NON_VOLATILE) == 0) {
1201 //
1202 // Query is Volatile related.
1203 //
1204 VariableStoreHeader = (VARIABLE_STORE_HEADER *) ((UINTN) Global->VolatileVariableBase);
1205 } else {
1206 //
1207 // Query is Non-Volatile related.
1208 //
1209 VariableStoreHeader = (VARIABLE_STORE_HEADER *) ((UINTN) Global->NonVolatileVariableBase);
1210 }
1211
1212 //
1213 // Now let's fill *MaximumVariableStorageSize *RemainingVariableStorageSize
1214 // with the storage size (excluding the storage header size).
1215 //
1216 *MaximumVariableStorageSize = VariableStoreHeader->Size - sizeof (VARIABLE_STORE_HEADER);
1217 *RemainingVariableStorageSize = VariableStoreHeader->Size - sizeof (VARIABLE_STORE_HEADER);
1218
1219 //
1220 // Let *MaximumVariableSize be MAX_VARIABLE_SIZE.
1221 //
1222 *MaximumVariableSize = MAX_VARIABLE_SIZE;
1223
1224 //
1225 // Point to the starting address of the variables.
1226 //
1227 Variable = (VARIABLE_HEADER *) (VariableStoreHeader + 1);
1228
1229 //
1230 // Now walk through the related variable store.
1231 //
1232 while (IsValidVariableHeader (Variable) && (Variable < GetEndPointer (VariableStoreHeader))) {
1233 NextVariable = GetNextVariablePtr (Variable);
1234 VariableSize = (UINT64) (UINTN) NextVariable - (UINT64) (UINTN) Variable;
1235
1236 if (EfiAtRuntime ()) {
1237 //
1238 // we don't take the state of the variables in mind
1239 // when calculating RemainingVariableStorageSize,
1240 // since the space occupied by variables not marked with
1241 // VAR_ADDED is not allowed to be reclaimed in Runtime.
1242 //
1243 *RemainingVariableStorageSize -= VariableSize;
1244 } else {
1245 //
1246 // Only care about Variables with State VAR_ADDED,because
1247 // the space not marked as VAR_ADDED is reclaimable now.
1248 //
1249 if (Variable->State == VAR_ADDED) {
1250 *RemainingVariableStorageSize -= VariableSize;
1251 }
1252 }
1253
1254 //
1255 // Go to the next one
1256 //
1257 Variable = NextVariable;
1258 }
1259
1260 ReleaseLockOnlyAtBootTime (&Global->VariableServicesLock);
1261 return EFI_SUCCESS;
1262 }
1263
1264 EFI_STATUS
1265 EFIAPI
1266 VariableCommonInitialize (
1267 IN EFI_HANDLE ImageHandle,
1268 IN EFI_SYSTEM_TABLE *SystemTable
1269 )
1270 /*++
1271
1272 Routine Description:
1273 This function does common initialization for variable services
1274
1275 Arguments:
1276
1277 ImageHandle - The firmware allocated handle for the EFI image.
1278 SystemTable - A pointer to the EFI System Table.
1279
1280 Returns:
1281
1282 Status code.
1283
1284 EFI_NOT_FOUND - Variable store area not found.
1285 EFI_UNSUPPORTED - Currently only one non-volatile variable store is supported.
1286 EFI_SUCCESS - Variable services successfully initialized.
1287
1288 --*/
1289 {
1290 EFI_STATUS Status;
1291 EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader;
1292 CHAR8 *CurrPtr;
1293 VARIABLE_STORE_HEADER *VolatileVariableStore;
1294 VARIABLE_STORE_HEADER *VariableStoreHeader;
1295 VARIABLE_HEADER *NextVariable;
1296 UINT32 Instance;
1297 EFI_PHYSICAL_ADDRESS FvVolHdr;
1298
1299 UINT64 TempVariableStoreHeader;
1300
1301 EFI_GCD_MEMORY_SPACE_DESCRIPTOR GcdDescriptor;
1302 EFI_FLASH_SUBAREA_ENTRY VariableStoreEntry;
1303 UINT64 BaseAddress;
1304 UINT64 Length;
1305 UINTN Index;
1306 UINT8 Data;
1307
1308 mVariableModuleGlobal = AllocateRuntimePool (sizeof (ESAL_VARIABLE_GLOBAL));
1309 if (mVariableModuleGlobal == NULL) {
1310 return EFI_OUT_OF_RESOURCES;
1311 }
1312
1313 EfiInitializeLock(&mVariableModuleGlobal->VariableGlobal[Physical].VariableServicesLock, TPL_NOTIFY);
1314
1315 //
1316 // Allocate memory for volatile variable store
1317 //
1318 VolatileVariableStore = AllocateRuntimePool (VARIABLE_STORE_SIZE + SCRATCH_SIZE);
1319 if (VolatileVariableStore == NULL) {
1320 FreePool (mVariableModuleGlobal);
1321 return EFI_OUT_OF_RESOURCES;
1322 }
1323
1324 SetMem (VolatileVariableStore, VARIABLE_STORE_SIZE + SCRATCH_SIZE, 0xff);
1325
1326 //
1327 // Variable Specific Data
1328 //
1329 mVariableModuleGlobal->VariableGlobal[Physical].VolatileVariableBase = (EFI_PHYSICAL_ADDRESS) (UINTN) VolatileVariableStore;
1330 mVariableModuleGlobal->VolatileLastVariableOffset = sizeof (VARIABLE_STORE_HEADER);
1331
1332 VolatileVariableStore->Signature = VARIABLE_STORE_SIGNATURE;
1333 VolatileVariableStore->Size = VARIABLE_STORE_SIZE;
1334 VolatileVariableStore->Format = VARIABLE_STORE_FORMATTED;
1335 VolatileVariableStore->State = VARIABLE_STORE_HEALTHY;
1336 VolatileVariableStore->Reserved = 0;
1337 VolatileVariableStore->Reserved1 = 0;
1338
1339 //
1340 // Get non volatile varaible store
1341 //
1342
1343 TempVariableStoreHeader = (UINT64) PcdGet32 (PcdFlashNvStorageVariableBase);
1344 VariableStoreEntry.Base = TempVariableStoreHeader + \
1345 (((EFI_FIRMWARE_VOLUME_HEADER *) (UINTN) (TempVariableStoreHeader)) -> HeaderLength);
1346 VariableStoreEntry.Length = (UINT64) PcdGet32 (PcdFlashNvStorageVariableSize) - \
1347 (((EFI_FIRMWARE_VOLUME_HEADER *) (UINTN) (TempVariableStoreHeader)) -> HeaderLength);
1348 //
1349 // Mark the variable storage region of the FLASH as RUNTIME
1350 //
1351 BaseAddress = VariableStoreEntry.Base & (~EFI_PAGE_MASK);
1352 Length = VariableStoreEntry.Length + (VariableStoreEntry.Base - BaseAddress);
1353 Length = (Length + EFI_PAGE_SIZE - 1) & (~EFI_PAGE_MASK);
1354
1355 Status = gDS->GetMemorySpaceDescriptor (BaseAddress, &GcdDescriptor);
1356 if (EFI_ERROR (Status)) {
1357 FreePool (mVariableModuleGlobal);
1358 FreePool (VolatileVariableStore);
1359 return EFI_UNSUPPORTED;
1360 }
1361
1362 Status = gDS->SetMemorySpaceAttributes (
1363 BaseAddress,
1364 Length,
1365 GcdDescriptor.Attributes | EFI_MEMORY_RUNTIME
1366 );
1367 if (EFI_ERROR (Status)) {
1368 FreePool (mVariableModuleGlobal);
1369 FreePool (VolatileVariableStore);
1370 return EFI_UNSUPPORTED;
1371 }
1372 //
1373 // Get address of non volatile variable store base
1374 //
1375 mVariableModuleGlobal->VariableGlobal[Physical].NonVolatileVariableBase = VariableStoreEntry.Base;
1376
1377 //
1378 // Check Integrity
1379 //
1380 //
1381 // Find the Correct Instance of the FV Block Service.
1382 //
1383 Instance = 0;
1384 CurrPtr = (CHAR8 *) ((UINTN) mVariableModuleGlobal->VariableGlobal[Physical].NonVolatileVariableBase);
1385 while (EfiFvbGetPhysicalAddress (Instance, &FvVolHdr) == EFI_SUCCESS) {
1386 FwVolHeader = (EFI_FIRMWARE_VOLUME_HEADER *) ((UINTN) FvVolHdr);
1387 if (CurrPtr >= (CHAR8 *) FwVolHeader && CurrPtr < (((CHAR8 *) FwVolHeader) + FwVolHeader->FvLength)) {
1388 mVariableModuleGlobal->FvbInstance = Instance;
1389 break;
1390 }
1391
1392 Instance++;
1393 }
1394
1395 VariableStoreHeader = (VARIABLE_STORE_HEADER *) CurrPtr;
1396 if (GetVariableStoreStatus (VariableStoreHeader) == EfiValid) {
1397 if (~VariableStoreHeader->Size == 0) {
1398 Status = UpdateVariableStore (
1399 &mVariableModuleGlobal->VariableGlobal[Physical],
1400 FALSE,
1401 FALSE,
1402 mVariableModuleGlobal->FvbInstance,
1403 (UINTN) &VariableStoreHeader->Size,
1404 sizeof (UINT32),
1405 (UINT8 *) &VariableStoreEntry.Length
1406 );
1407 //
1408 // As Variables are stored in NV storage, which are slow devices,such as flash.
1409 // Variable operation may skip checking variable program result to improve performance,
1410 // We can assume Variable program is OK through some check point.
1411 // Variable Store Size Setting should be the first Variable write operation,
1412 // We can assume all Read/Write is OK if we can set Variable store size successfully.
1413 // If write fail, we will assert here
1414 //
1415 ASSERT(VariableStoreHeader->Size == VariableStoreEntry.Length);
1416
1417 if (EFI_ERROR (Status)) {
1418 return Status;
1419 }
1420 }
1421
1422 mVariableModuleGlobal->VariableGlobal[Physical].NonVolatileVariableBase = (EFI_PHYSICAL_ADDRESS) ((UINTN) CurrPtr);
1423 //
1424 // Parse non-volatile variable data and get last variable offset
1425 //
1426 NextVariable = (VARIABLE_HEADER *) (CurrPtr + sizeof (VARIABLE_STORE_HEADER));
1427 Status = EFI_SUCCESS;
1428
1429 while (IsValidVariableHeader (NextVariable)) {
1430 NextVariable = GetNextVariablePtr (NextVariable);
1431 }
1432
1433 mVariableModuleGlobal->NonVolatileLastVariableOffset = (UINTN) NextVariable - (UINTN) CurrPtr;
1434
1435 //
1436 // Check if the free area is blow a threshold
1437 //
1438 if ((((VARIABLE_STORE_HEADER *)((UINTN) CurrPtr))->Size - mVariableModuleGlobal->NonVolatileLastVariableOffset) < VARIABLE_RECLAIM_THRESHOLD) {
1439 Status = Reclaim (
1440 mVariableModuleGlobal->VariableGlobal[Physical].NonVolatileVariableBase,
1441 &mVariableModuleGlobal->NonVolatileLastVariableOffset,
1442 FALSE
1443 );
1444 }
1445
1446 if (EFI_ERROR (Status)) {
1447 FreePool (mVariableModuleGlobal);
1448 FreePool (VolatileVariableStore);
1449 return Status;
1450 }
1451
1452 //
1453 // Check if the free area is really free.
1454 //
1455 for (Index = mVariableModuleGlobal->NonVolatileLastVariableOffset; Index < VariableStoreHeader->Size; Index++) {
1456 Data = ((UINT8 *) (UINTN) mVariableModuleGlobal->VariableGlobal[Physical].NonVolatileVariableBase)[Index];
1457 if (Data != 0xff) {
1458 //
1459 // There must be something wrong in variable store, do reclaim operation.
1460 //
1461 Status = Reclaim (
1462 mVariableModuleGlobal->VariableGlobal[Physical].NonVolatileVariableBase,
1463 &mVariableModuleGlobal->NonVolatileLastVariableOffset,
1464 FALSE
1465 );
1466 break;
1467 }
1468 }
1469 }
1470
1471 if (EFI_ERROR (Status)) {
1472 FreePool (mVariableModuleGlobal);
1473 FreePool (VolatileVariableStore);
1474 }
1475
1476 return Status;
1477 }