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