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