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