Change the TPL lock level to EFI_TPL_NOTIFY. Variable Service is called in ResetSyste...
[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 Status = gBS->AllocatePool (
428 EfiBootServicesData,
429 ValidBufferSize,
430 (VOID **) &ValidBuffer
431 );
432 if (EFI_ERROR (Status)) {
433 return Status;
434 }
435
436 SetMem (ValidBuffer, ValidBufferSize, 0xff);
437
438 CurrPtr = ValidBuffer;
439
440 //
441 // Copy variable store header
442 //
443 CopyMem (CurrPtr, VariableStoreHeader, sizeof (VARIABLE_STORE_HEADER));
444 CurrPtr += sizeof (VARIABLE_STORE_HEADER);
445
446 //
447 // Start Pointers for the variable.
448 //
449 Variable = (VARIABLE_HEADER *) (VariableStoreHeader + 1);
450
451 while (IsValidVariableHeader (Variable)) {
452 NextVariable = GetNextVariablePtr (Variable);
453 if (Variable->State == VAR_ADDED) {
454 VariableSize = (UINTN) NextVariable - (UINTN) Variable;
455 CopyMem (CurrPtr, (UINT8 *) Variable, VariableSize);
456 CurrPtr += VariableSize;
457 }
458
459 Variable = NextVariable;
460 }
461
462 if (IsVolatile) {
463 //
464 // If volatile variable store, just copy valid buffer
465 //
466 SetMem ((UINT8 *) (UINTN) VariableBase, VariableStoreHeader->Size, 0xff);
467 CopyMem ((UINT8 *) (UINTN) VariableBase, ValidBuffer, ValidBufferSize);
468 *LastVariableOffset = ValidBufferSize;
469 Status = EFI_SUCCESS;
470 } else {
471 //
472 // If non-volatile variable store, perform FTW here.
473 //
474 Status = FtwVariableSpace (
475 VariableBase,
476 ValidBuffer,
477 ValidBufferSize
478 );
479 if (!EFI_ERROR (Status)) {
480 *LastVariableOffset = ValidBufferSize;
481 }
482 }
483
484 gBS->FreePool (ValidBuffer);
485
486 if (EFI_ERROR (Status)) {
487 *LastVariableOffset = 0;
488 }
489
490 return Status;
491 }
492
493 STATIC
494 EFI_STATUS
495 EFIAPI
496 FindVariable (
497 IN CHAR16 *VariableName,
498 IN EFI_GUID *VendorGuid,
499 OUT VARIABLE_POINTER_TRACK *PtrTrack,
500 IN VARIABLE_GLOBAL *Global
501 )
502 /*++
503
504 Routine Description:
505
506 This code finds variable in storage blocks (Volatile or Non-Volatile)
507
508 Arguments:
509
510 VariableName Name of the variable to be found
511 VendorGuid Vendor GUID to be found.
512 PtrTrack Variable Track Pointer structure that contains
513 Variable Information.
514 Contains the pointer of Variable header.
515 Global VARIABLE_GLOBAL pointer
516
517 Returns:
518
519 EFI STATUS
520
521 --*/
522 {
523 VARIABLE_HEADER *Variable[2];
524 VARIABLE_STORE_HEADER *VariableStoreHeader[2];
525 UINTN Index;
526
527 //
528 // We aquire the lock at the entry of FindVariable as GetVariable, GetNextVariableName
529 // SetVariable all call FindVariable at entry point. Please move "Aquire Lock" to
530 // the correct places if this assumption does not hold TRUE anymore.
531 //
532 AcquireLockOnlyAtBootTime(&Global->VariableServicesLock);
533
534 //
535 // 0: Non-Volatile, 1: Volatile
536 //
537 VariableStoreHeader[0] = (VARIABLE_STORE_HEADER *) ((UINTN) Global->NonVolatileVariableBase);
538 VariableStoreHeader[1] = (VARIABLE_STORE_HEADER *) ((UINTN) Global->VolatileVariableBase);
539
540 //
541 // Start Pointers for the variable.
542 // Actual Data Pointer where data can be written.
543 //
544 Variable[0] = (VARIABLE_HEADER *) (VariableStoreHeader[0] + 1);
545 Variable[1] = (VARIABLE_HEADER *) (VariableStoreHeader[1] + 1);
546
547 if (VariableName[0] != 0 && VendorGuid == NULL) {
548 return EFI_INVALID_PARAMETER;
549 }
550 //
551 // Find the variable by walk through non-volatile and volatile variable store
552 //
553 for (Index = 0; Index < 2; Index++) {
554 PtrTrack->StartPtr = (VARIABLE_HEADER *) (VariableStoreHeader[Index] + 1);
555 PtrTrack->EndPtr = GetEndPointer (VariableStoreHeader[Index]);
556
557 while (IsValidVariableHeader (Variable[Index]) && (Variable[Index] <= GetEndPointer (VariableStoreHeader[Index]))) {
558 if (Variable[Index]->State == VAR_ADDED) {
559 if (!(EfiAtRuntime () && !(Variable[Index]->Attributes & EFI_VARIABLE_RUNTIME_ACCESS))) {
560 if (VariableName[0] == 0) {
561 PtrTrack->CurrPtr = Variable[Index];
562 PtrTrack->Volatile = (BOOLEAN) Index;
563 return EFI_SUCCESS;
564 } else {
565 if (CompareGuid (VendorGuid, &Variable[Index]->VendorGuid)) {
566 if (!CompareMem (VariableName, GET_VARIABLE_NAME_PTR (Variable[Index]), Variable[Index]->NameSize)) {
567 PtrTrack->CurrPtr = Variable[Index];
568 PtrTrack->Volatile = (BOOLEAN) Index;
569 return EFI_SUCCESS;
570 }
571 }
572 }
573 }
574 }
575
576 Variable[Index] = GetNextVariablePtr (Variable[Index]);
577 }
578 //
579 // While (...)
580 //
581 }
582 //
583 // for (...)
584 //
585 PtrTrack->CurrPtr = NULL;
586 return EFI_NOT_FOUND;
587 }
588
589 EFI_STATUS
590 EFIAPI
591 GetVariable (
592 IN CHAR16 *VariableName,
593 IN EFI_GUID * VendorGuid,
594 OUT UINT32 *Attributes OPTIONAL,
595 IN OUT UINTN *DataSize,
596 OUT VOID *Data,
597 IN VARIABLE_GLOBAL * Global,
598 IN UINT32 Instance
599 )
600 /*++
601
602 Routine Description:
603
604 This code finds variable in storage blocks (Volatile or Non-Volatile)
605
606 Arguments:
607
608 VariableName Name of Variable to be found
609 VendorGuid Variable vendor GUID
610 Attributes OPTIONAL Attribute value of the variable found
611 DataSize Size of Data found. If size is less than the
612 data, this value contains the required size.
613 Data Data pointer
614 Global Pointer to VARIABLE_GLOBAL structure
615 Instance Instance of the Firmware Volume.
616
617 Returns:
618
619 EFI STATUS
620
621 --*/
622 {
623 VARIABLE_POINTER_TRACK Variable;
624 UINTN VarDataSize;
625 EFI_STATUS Status;
626
627 if (VariableName == NULL || VendorGuid == NULL || DataSize == NULL) {
628 return EFI_INVALID_PARAMETER;
629 }
630 //
631 // Find existing variable
632 //
633 Status = FindVariable (VariableName, VendorGuid, &Variable, Global);
634
635 if (Variable.CurrPtr == NULL || EFI_ERROR (Status)) {
636 goto Done;
637 }
638 //
639 // Get data size
640 //
641 VarDataSize = Variable.CurrPtr->DataSize;
642 if (*DataSize >= VarDataSize) {
643 if (Data == NULL) {
644 Status = EFI_INVALID_PARAMETER;
645 goto Done;
646 }
647
648 CopyMem (Data, GetVariableDataPtr (Variable.CurrPtr), VarDataSize);
649 if (Attributes != NULL) {
650 *Attributes = Variable.CurrPtr->Attributes;
651 }
652
653 *DataSize = VarDataSize;
654 Status = EFI_SUCCESS;
655 goto Done;
656 } else {
657 *DataSize = VarDataSize;
658 Status = EFI_BUFFER_TOO_SMALL;
659 goto Done;
660 }
661
662 Done:
663 ReleaseLockOnlyAtBootTime (&Global->VariableServicesLock);
664 return Status;
665 }
666
667 EFI_STATUS
668 EFIAPI
669 GetNextVariableName (
670 IN OUT UINTN *VariableNameSize,
671 IN OUT CHAR16 *VariableName,
672 IN OUT EFI_GUID *VendorGuid,
673 IN VARIABLE_GLOBAL *Global,
674 IN UINT32 Instance
675 )
676 /*++
677
678 Routine Description:
679
680 This code Finds the Next available variable
681
682 Arguments:
683
684 VariableNameSize Size of the variable
685 VariableName Pointer to variable name
686 VendorGuid Variable Vendor Guid
687 Global VARIABLE_GLOBAL structure pointer.
688 Instance FV instance
689
690 Returns:
691
692 EFI STATUS
693
694 --*/
695 {
696 VARIABLE_POINTER_TRACK Variable;
697 UINTN VarNameSize;
698 EFI_STATUS Status;
699
700 if (VariableNameSize == NULL || VariableName == NULL || VendorGuid == NULL) {
701 return EFI_INVALID_PARAMETER;
702 }
703
704 Status = FindVariable (VariableName, VendorGuid, &Variable, Global);
705
706 if (Variable.CurrPtr == NULL || EFI_ERROR (Status)) {
707 goto Done;
708 }
709
710 if (VariableName[0] != 0) {
711 //
712 // If variable name is not NULL, get next variable
713 //
714 Variable.CurrPtr = GetNextVariablePtr (Variable.CurrPtr);
715 }
716
717 while (TRUE) {
718 //
719 // If both volatile and non-volatile variable store are parsed,
720 // return not found
721 //
722 if (Variable.CurrPtr >= Variable.EndPtr || Variable.CurrPtr == NULL) {
723 Variable.Volatile = (BOOLEAN) (Variable.Volatile ^ ((BOOLEAN) 0x1));
724 if (Variable.Volatile) {
725 Variable.StartPtr = (VARIABLE_HEADER *) ((UINTN) (Global->VolatileVariableBase + sizeof (VARIABLE_STORE_HEADER)));
726 Variable.EndPtr = (VARIABLE_HEADER *) GetEndPointer ((VARIABLE_STORE_HEADER *) ((UINTN) Global->VolatileVariableBase));
727 } else {
728 Status = EFI_NOT_FOUND;
729 goto Done;
730 }
731
732 Variable.CurrPtr = Variable.StartPtr;
733 if (!IsValidVariableHeader (Variable.CurrPtr)) {
734 continue;
735 }
736 }
737 //
738 // Variable is found
739 //
740 if (IsValidVariableHeader (Variable.CurrPtr) && Variable.CurrPtr->State == VAR_ADDED) {
741 if (!(EfiAtRuntime () && !(Variable.CurrPtr->Attributes & EFI_VARIABLE_RUNTIME_ACCESS))) {
742 VarNameSize = Variable.CurrPtr->NameSize;
743 if (VarNameSize <= *VariableNameSize) {
744 CopyMem (
745 VariableName,
746 GET_VARIABLE_NAME_PTR (Variable.CurrPtr),
747 VarNameSize
748 );
749 CopyMem (
750 VendorGuid,
751 &Variable.CurrPtr->VendorGuid,
752 sizeof (EFI_GUID)
753 );
754 Status = EFI_SUCCESS;
755 } else {
756 Status = EFI_BUFFER_TOO_SMALL;
757 }
758
759 *VariableNameSize = VarNameSize;
760 goto Done;
761 }
762 }
763
764 Variable.CurrPtr = GetNextVariablePtr (Variable.CurrPtr);
765 }
766
767 Done:
768 ReleaseLockOnlyAtBootTime (&Global->VariableServicesLock);
769 return Status;
770 }
771
772 EFI_STATUS
773 EFIAPI
774 SetVariable (
775 IN CHAR16 *VariableName,
776 IN EFI_GUID *VendorGuid,
777 IN UINT32 Attributes,
778 IN UINTN DataSize,
779 IN VOID *Data,
780 IN VARIABLE_GLOBAL *Global,
781 IN UINTN *VolatileOffset,
782 IN UINTN *NonVolatileOffset,
783 IN UINT32 Instance
784 )
785 /*++
786
787 Routine Description:
788
789 This code sets variable in storage blocks (Volatile or Non-Volatile)
790
791 Arguments:
792
793 VariableName Name of Variable to be found
794 VendorGuid Variable vendor GUID
795 Attributes Attribute value of the variable found
796 DataSize Size of Data found. If size is less than the
797 data, this value contains the required size.
798 Data Data pointer
799 Global Pointer to VARIABLE_GLOBAL structure
800 VolatileOffset The offset of last volatile variable
801 NonVolatileOffset The offset of last non-volatile variable
802 Instance Instance of the Firmware Volume.
803
804 Returns:
805
806 EFI STATUS
807 EFI_INVALID_PARAMETER - Invalid parameter
808 EFI_SUCCESS - Set successfully
809 EFI_OUT_OF_RESOURCES - Resource not enough to set variable
810 EFI_NOT_FOUND - Not found
811
812 --*/
813 {
814 VARIABLE_POINTER_TRACK Variable;
815 EFI_STATUS Status;
816 VARIABLE_HEADER *NextVariable;
817 UINTN VarNameSize;
818 UINTN VarNameOffset;
819 UINTN VarDataOffset;
820 UINTN VarSize;
821 UINT8 State;
822 BOOLEAN Reclaimed;
823
824 Reclaimed = FALSE;
825
826 if (VariableName == NULL || VariableName[0] == 0 || VendorGuid == NULL) {
827 return EFI_INVALID_PARAMETER;
828 }
829
830 Status = FindVariable (VariableName, VendorGuid, &Variable, Global);
831
832 if (Status == EFI_INVALID_PARAMETER) {
833 goto Done;
834 } else if (!EFI_ERROR (Status) && Variable.Volatile && EfiAtRuntime()) {
835 //
836 // If EfiAtRuntime and the variable is Volatile and Runtime Access,
837 // the volatile is ReadOnly, and SetVariable should be aborted and
838 // return EFI_WRITE_PROTECTED.
839 //
840 Status = EFI_WRITE_PROTECTED;
841 goto Done;
842 } else if (sizeof (VARIABLE_HEADER) + StrSize (VariableName) + DataSize > MAX_VARIABLE_SIZE) {
843 //
844 // The size of the VariableName, including the Unicode Null in bytes plus
845 // the DataSize is limited to maximum size of MAX_VARIABLE_SIZE (1024) bytes.
846 //
847 Status = EFI_INVALID_PARAMETER;
848 goto Done;
849 } else if (Attributes == EFI_VARIABLE_NON_VOLATILE) {
850 //
851 // Make sure not only EFI_VARIABLE_NON_VOLATILE is set
852 //
853 Status = EFI_INVALID_PARAMETER;
854 goto Done;
855 } else if ((Attributes & (EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS)) ==
856 EFI_VARIABLE_RUNTIME_ACCESS) {
857 //
858 // Make sure if runtime bit is set, boot service bit is set also
859 //
860 Status = EFI_INVALID_PARAMETER;
861 goto Done;
862 } else if (EfiAtRuntime () && Attributes && !(Attributes & EFI_VARIABLE_RUNTIME_ACCESS)) {
863 //
864 // Runtime but Attribute is not Runtime
865 //
866 Status = EFI_INVALID_PARAMETER;
867 goto Done;
868 } else if (EfiAtRuntime () && Attributes && !(Attributes & EFI_VARIABLE_NON_VOLATILE)) {
869 //
870 // Cannot set volatile variable in Runtime
871 //
872 Status = EFI_INVALID_PARAMETER;
873 goto Done;
874 } else if (DataSize == 0 || (Attributes & (EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS)) == 0) {
875 //
876 // Setting a data variable with no access, or zero DataSize attributes
877 // specified causes it to be deleted.
878 //
879 if (!EFI_ERROR (Status)) {
880 State = Variable.CurrPtr->State;
881 State &= VAR_DELETED;
882
883 Status = UpdateVariableStore (
884 Global,
885 Variable.Volatile,
886 FALSE,
887 Instance,
888 (UINTN) &Variable.CurrPtr->State,
889 sizeof (UINT8),
890 &State
891 );
892 if (EFI_ERROR (Status)) {
893 goto Done;
894 }
895
896 Status = EFI_SUCCESS;
897 goto Done;
898 }
899
900 Status = EFI_NOT_FOUND;
901 goto Done;
902 } else {
903 if (!EFI_ERROR (Status)) {
904 //
905 // If the variable is marked valid and the same data has been passed in
906 // then return to the caller immediately.
907 //
908 if (Variable.CurrPtr->DataSize == DataSize &&
909 !CompareMem (Data, GetVariableDataPtr (Variable.CurrPtr), DataSize)
910 ) {
911 Status = EFI_SUCCESS;
912 goto Done;
913 } else if (Variable.CurrPtr->State == VAR_ADDED) {
914 //
915 // Mark the old variable as in delete transition
916 //
917 State = Variable.CurrPtr->State;
918 State &= VAR_IN_DELETED_TRANSITION;
919
920 Status = UpdateVariableStore (
921 Global,
922 Variable.Volatile,
923 FALSE,
924 Instance,
925 (UINTN) &Variable.CurrPtr->State,
926 sizeof (UINT8),
927 &State
928 );
929 if (EFI_ERROR (Status)) {
930 goto Done;
931 }
932 }
933 }
934 //
935 // Create a new variable and copy the data.
936 //
937 // Tricky part: Use scratch data area at the end of volatile variable store
938 // as a temporary storage.
939 //
940 NextVariable = GetEndPointer ((VARIABLE_STORE_HEADER *) ((UINTN) Global->VolatileVariableBase));
941
942 SetMem (NextVariable, SCRATCH_SIZE, 0xff);
943
944 NextVariable->StartId = VARIABLE_DATA;
945 NextVariable->Attributes = Attributes;
946 //
947 // NextVariable->State = VAR_ADDED;
948 //
949 NextVariable->Reserved = 0;
950 VarNameOffset = sizeof (VARIABLE_HEADER);
951 VarNameSize = StrSize (VariableName);
952 CopyMem (
953 (UINT8 *) ((UINTN) NextVariable + VarNameOffset),
954 VariableName,
955 VarNameSize
956 );
957 VarDataOffset = VarNameOffset + VarNameSize + GET_PAD_SIZE (VarNameSize);
958 CopyMem (
959 (UINT8 *) ((UINTN) NextVariable + VarDataOffset),
960 Data,
961 DataSize
962 );
963 CopyMem (&NextVariable->VendorGuid, VendorGuid, sizeof (EFI_GUID));
964 //
965 // There will be pad bytes after Data, the NextVariable->NameSize and
966 // NextVariable->DataSize should not include pad size so that variable
967 // service can get actual size in GetVariable
968 //
969 NextVariable->NameSize = (UINT32)VarNameSize;
970 NextVariable->DataSize = (UINT32)DataSize;
971
972 //
973 // The actual size of the variable that stores in storage should
974 // include pad size.
975 //
976 VarSize = VarDataOffset + DataSize + GET_PAD_SIZE (DataSize);
977 if (Attributes & EFI_VARIABLE_NON_VOLATILE) {
978 if ((UINT32) (VarSize +*NonVolatileOffset) >
979 ((VARIABLE_STORE_HEADER *) ((UINTN) (Global->NonVolatileVariableBase)))->Size
980 ) {
981 if (EfiAtRuntime ()) {
982 Status = EFI_OUT_OF_RESOURCES;
983 goto Done;
984 }
985 //
986 // Perform garbage collection & reclaim operation
987 //
988 Status = Reclaim (Global->NonVolatileVariableBase, NonVolatileOffset, FALSE);
989 if (EFI_ERROR (Status)) {
990 goto Done;
991 }
992 //
993 // If still no enough space, return out of resources
994 //
995 if ((UINT32) (VarSize +*NonVolatileOffset) >
996 ((VARIABLE_STORE_HEADER *) ((UINTN) (Global->NonVolatileVariableBase)))->Size
997 ) {
998 Status = EFI_OUT_OF_RESOURCES;
999 goto Done;
1000 }
1001
1002 Reclaimed = TRUE;
1003 }
1004 //
1005 // Three steps
1006 // 1. Write variable header
1007 // 2. Write variable data
1008 // 3. Set variable state to valid
1009 //
1010 //
1011 // Step 1:
1012 //
1013 Status = UpdateVariableStore (
1014 Global,
1015 FALSE,
1016 TRUE,
1017 Instance,
1018 *NonVolatileOffset,
1019 sizeof (VARIABLE_HEADER),
1020 (UINT8 *) NextVariable
1021 );
1022
1023 if (EFI_ERROR (Status)) {
1024 goto Done;
1025 }
1026 //
1027 // Step 2:
1028 //
1029 Status = UpdateVariableStore (
1030 Global,
1031 FALSE,
1032 TRUE,
1033 Instance,
1034 *NonVolatileOffset + sizeof (VARIABLE_HEADER),
1035 (UINT32) VarSize - sizeof (VARIABLE_HEADER),
1036 (UINT8 *) NextVariable + sizeof (VARIABLE_HEADER)
1037 );
1038
1039 if (EFI_ERROR (Status)) {
1040 goto Done;
1041 }
1042 //
1043 // Step 3:
1044 //
1045 NextVariable->State = VAR_ADDED;
1046 Status = UpdateVariableStore (
1047 Global,
1048 FALSE,
1049 TRUE,
1050 Instance,
1051 *NonVolatileOffset,
1052 sizeof (VARIABLE_HEADER),
1053 (UINT8 *) NextVariable
1054 );
1055
1056 if (EFI_ERROR (Status)) {
1057 goto Done;
1058 }
1059
1060 *NonVolatileOffset = *NonVolatileOffset + VarSize;
1061
1062 } else {
1063 if (EfiAtRuntime ()) {
1064 Status = EFI_INVALID_PARAMETER;
1065 goto Done;
1066 }
1067
1068 if ((UINT32) (VarSize +*VolatileOffset) >
1069 ((VARIABLE_STORE_HEADER *) ((UINTN) (Global->VolatileVariableBase)))->Size
1070 ) {
1071 //
1072 // Perform garbage collection & reclaim operation
1073 //
1074 Status = Reclaim (Global->VolatileVariableBase, VolatileOffset, TRUE);
1075 if (EFI_ERROR (Status)) {
1076 goto Done;
1077 }
1078 //
1079 // If still no enough space, return out of resources
1080 //
1081 if ((UINT32) (VarSize +*VolatileOffset) >
1082 ((VARIABLE_STORE_HEADER *) ((UINTN) (Global->VolatileVariableBase)))->Size
1083 ) {
1084 Status = EFI_OUT_OF_RESOURCES;
1085 goto Done;
1086 }
1087
1088 Reclaimed = TRUE;
1089 }
1090
1091 NextVariable->State = VAR_ADDED;
1092 Status = UpdateVariableStore (
1093 Global,
1094 TRUE,
1095 TRUE,
1096 Instance,
1097 *VolatileOffset,
1098 (UINT32) VarSize,
1099 (UINT8 *) NextVariable
1100 );
1101
1102 if (EFI_ERROR (Status)) {
1103 goto Done;
1104 }
1105
1106 *VolatileOffset = *VolatileOffset + VarSize;
1107 }
1108 //
1109 // Mark the old variable as deleted
1110 //
1111 if (!Reclaimed && !EFI_ERROR (Status) && Variable.CurrPtr != NULL) {
1112 State = Variable.CurrPtr->State;
1113 State &= VAR_DELETED;
1114
1115 Status = UpdateVariableStore (
1116 Global,
1117 Variable.Volatile,
1118 FALSE,
1119 Instance,
1120 (UINTN) &Variable.CurrPtr->State,
1121 sizeof (UINT8),
1122 &State
1123 );
1124
1125 if (EFI_ERROR (Status)) {
1126 goto Done;
1127 }
1128 }
1129 }
1130
1131 Status = EFI_SUCCESS;
1132 Done:
1133 ReleaseLockOnlyAtBootTime (&Global->VariableServicesLock);
1134 return Status;
1135 }
1136
1137 #if (EFI_SPECIFICATION_VERSION >= 0x00020000)
1138 EFI_STATUS
1139 EFIAPI
1140 QueryVariableInfo (
1141 IN UINT32 Attributes,
1142 OUT UINT64 *MaximumVariableStorageSize,
1143 OUT UINT64 *RemainingVariableStorageSize,
1144 OUT UINT64 *MaximumVariableSize,
1145 IN VARIABLE_GLOBAL *Global,
1146 IN UINT32 Instance
1147 )
1148 /*++
1149
1150 Routine Description:
1151
1152 This code returns information about the EFI variables.
1153
1154 Arguments:
1155
1156 Attributes Attributes bitmask to specify the type of variables
1157 on which to return information.
1158 MaximumVariableStorageSize Pointer to the maximum size of the storage space available
1159 for the EFI variables associated with the attributes specified.
1160 RemainingVariableStorageSize Pointer to the remaining size of the storage space available
1161 for the EFI variables associated with the attributes specified.
1162 MaximumVariableSize Pointer to the maximum size of the individual EFI variables
1163 associated with the attributes specified.
1164 Global Pointer to VARIABLE_GLOBAL structure.
1165 Instance Instance of the Firmware Volume.
1166
1167 Returns:
1168
1169 EFI STATUS
1170 EFI_INVALID_PARAMETER - An invalid combination of attribute bits was supplied.
1171 EFI_SUCCESS - Query successfully.
1172 EFI_UNSUPPORTED - The attribute is not supported on this platform.
1173
1174 --*/
1175 {
1176 VARIABLE_HEADER *Variable;
1177 VARIABLE_HEADER *NextVariable;
1178 UINT64 VariableSize;
1179 VARIABLE_STORE_HEADER *VariableStoreHeader;
1180
1181 if(MaximumVariableStorageSize == NULL || RemainingVariableStorageSize == NULL || MaximumVariableSize == NULL) {
1182 return EFI_INVALID_PARAMETER;
1183 }
1184
1185 if((Attributes & (EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS)) == 0) {
1186 //
1187 // Make sure the Attributes combination is supported by the platform.
1188 //
1189 return EFI_UNSUPPORTED;
1190 } else if ((Attributes & (EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS)) == EFI_VARIABLE_RUNTIME_ACCESS) {
1191 //
1192 // Make sure if runtime bit is set, boot service bit is set also.
1193 //
1194 return EFI_INVALID_PARAMETER;
1195 } else if (EfiAtRuntime () && !(Attributes & EFI_VARIABLE_RUNTIME_ACCESS)) {
1196 //
1197 // Make sure RT Attribute is set if we are in Runtime phase.
1198 //
1199 return EFI_INVALID_PARAMETER;
1200 }
1201
1202 AcquireLockOnlyAtBootTime(&Global->VariableServicesLock);
1203
1204 if((Attributes & EFI_VARIABLE_NON_VOLATILE) == 0) {
1205 //
1206 // Query is Volatile related.
1207 //
1208 VariableStoreHeader = (VARIABLE_STORE_HEADER *) ((UINTN) Global->VolatileVariableBase);
1209 } else {
1210 //
1211 // Query is Non-Volatile related.
1212 //
1213 VariableStoreHeader = (VARIABLE_STORE_HEADER *) ((UINTN) Global->NonVolatileVariableBase);
1214 }
1215
1216 //
1217 // Now let's fill *MaximumVariableStorageSize *RemainingVariableStorageSize
1218 // with the storage size (excluding the storage header size).
1219 //
1220 *MaximumVariableStorageSize = VariableStoreHeader->Size - sizeof (VARIABLE_STORE_HEADER);
1221 *RemainingVariableStorageSize = VariableStoreHeader->Size - sizeof (VARIABLE_STORE_HEADER);
1222
1223 //
1224 // Let *MaximumVariableSize be MAX_VARIABLE_SIZE.
1225 //
1226 *MaximumVariableSize = MAX_VARIABLE_SIZE;
1227
1228 //
1229 // Point to the starting address of the variables.
1230 //
1231 Variable = (VARIABLE_HEADER *) (VariableStoreHeader + 1);
1232
1233 //
1234 // Now walk through the related variable store.
1235 //
1236 while (IsValidVariableHeader (Variable) && (Variable < GetEndPointer (VariableStoreHeader))) {
1237 NextVariable = GetNextVariablePtr (Variable);
1238 VariableSize = (UINT64) (UINTN) NextVariable - (UINT64) (UINTN) Variable;
1239
1240 if (EfiAtRuntime ()) {
1241 //
1242 // we don't take the state of the variables in mind
1243 // when calculating RemainingVariableStorageSize,
1244 // since the space occupied by variables not marked with
1245 // VAR_ADDED is not allowed to be reclaimed in Runtime.
1246 //
1247 *RemainingVariableStorageSize -= VariableSize;
1248 } else {
1249 //
1250 // Only care about Variables with State VAR_ADDED,because
1251 // the space not marked as VAR_ADDED is reclaimable now.
1252 //
1253 if (Variable->State == VAR_ADDED) {
1254 *RemainingVariableStorageSize -= VariableSize;
1255 }
1256 }
1257
1258 //
1259 // Go to the next one
1260 //
1261 Variable = NextVariable;
1262 }
1263
1264 ReleaseLockOnlyAtBootTime (&Global->VariableServicesLock);
1265 return EFI_SUCCESS;
1266 }
1267 #endif
1268
1269 EFI_STATUS
1270 EFIAPI
1271 VariableCommonInitialize (
1272 IN EFI_HANDLE ImageHandle,
1273 IN EFI_SYSTEM_TABLE *SystemTable
1274 )
1275 /*++
1276
1277 Routine Description:
1278 This function does common initialization for variable services
1279
1280 Arguments:
1281
1282 ImageHandle - The firmware allocated handle for the EFI image.
1283 SystemTable - A pointer to the EFI System Table.
1284
1285 Returns:
1286
1287 Status code.
1288
1289 EFI_NOT_FOUND - Variable store area not found.
1290 EFI_UNSUPPORTED - Currently only one non-volatile variable store is supported.
1291 EFI_SUCCESS - Variable services successfully initialized.
1292
1293 --*/
1294 {
1295 EFI_STATUS Status;
1296 EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader;
1297 CHAR8 *CurrPtr;
1298 VARIABLE_STORE_HEADER *VolatileVariableStore;
1299 VARIABLE_STORE_HEADER *VariableStoreHeader;
1300 VARIABLE_HEADER *NextVariable;
1301 UINT32 Instance;
1302 EFI_PHYSICAL_ADDRESS FvVolHdr;
1303
1304 UINT64 TempVariableStoreHeader;
1305
1306 EFI_GCD_MEMORY_SPACE_DESCRIPTOR GcdDescriptor;
1307 EFI_FLASH_SUBAREA_ENTRY VariableStoreEntry;
1308 UINT64 BaseAddress;
1309 UINT64 Length;
1310 UINTN Index;
1311 UINT8 Data;
1312
1313 Status = gBS->AllocatePool (
1314 EfiRuntimeServicesData,
1315 sizeof (ESAL_VARIABLE_GLOBAL),
1316 (VOID **) &mVariableModuleGlobal
1317 );
1318
1319 if (EFI_ERROR (Status)) {
1320 return Status;
1321 }
1322
1323 EfiInitializeLock(&mVariableModuleGlobal->VariableGlobal[Physical].VariableServicesLock, EFI_TPL_NOTIFY);
1324
1325 //
1326 // Allocate memory for volatile variable store
1327 //
1328 Status = gBS->AllocatePool (
1329 EfiRuntimeServicesData,
1330 VARIABLE_STORE_SIZE + SCRATCH_SIZE,
1331 (VOID **) &VolatileVariableStore
1332 );
1333
1334 if (EFI_ERROR (Status)) {
1335 gBS->FreePool (mVariableModuleGlobal);
1336 return Status;
1337 }
1338
1339 SetMem (VolatileVariableStore, VARIABLE_STORE_SIZE + SCRATCH_SIZE, 0xff);
1340
1341 //
1342 // Variable Specific Data
1343 //
1344 mVariableModuleGlobal->VariableGlobal[Physical].VolatileVariableBase = (EFI_PHYSICAL_ADDRESS) (UINTN) VolatileVariableStore;
1345 mVariableModuleGlobal->VolatileLastVariableOffset = sizeof (VARIABLE_STORE_HEADER);
1346
1347 VolatileVariableStore->Signature = VARIABLE_STORE_SIGNATURE;
1348 VolatileVariableStore->Size = VARIABLE_STORE_SIZE;
1349 VolatileVariableStore->Format = VARIABLE_STORE_FORMATTED;
1350 VolatileVariableStore->State = VARIABLE_STORE_HEALTHY;
1351 VolatileVariableStore->Reserved = 0;
1352 VolatileVariableStore->Reserved1 = 0;
1353
1354 //
1355 // Get non volatile varaible store
1356 //
1357
1358 TempVariableStoreHeader = (UINT64) PcdGet32 (PcdFlashNvStorageVariableBase);
1359 VariableStoreEntry.Base = TempVariableStoreHeader + \
1360 (((EFI_FIRMWARE_VOLUME_HEADER *) (UINTN) (TempVariableStoreHeader)) -> HeaderLength);
1361 VariableStoreEntry.Length = (UINT64) PcdGet32 (PcdFlashNvStorageVariableSize) - \
1362 (((EFI_FIRMWARE_VOLUME_HEADER *) (UINTN) (TempVariableStoreHeader)) -> HeaderLength);
1363 //
1364 // Mark the variable storage region of the FLASH as RUNTIME
1365 //
1366 BaseAddress = VariableStoreEntry.Base & (~EFI_PAGE_MASK);
1367 Length = VariableStoreEntry.Length + (VariableStoreEntry.Base - BaseAddress);
1368 Length = (Length + EFI_PAGE_SIZE - 1) & (~EFI_PAGE_MASK);
1369
1370 Status = gDS->GetMemorySpaceDescriptor (BaseAddress, &GcdDescriptor);
1371 if (EFI_ERROR (Status)) {
1372 gBS->FreePool (mVariableModuleGlobal);
1373 gBS->FreePool (VolatileVariableStore);
1374 return EFI_UNSUPPORTED;
1375 }
1376
1377 Status = gDS->SetMemorySpaceAttributes (
1378 BaseAddress,
1379 Length,
1380 GcdDescriptor.Attributes | EFI_MEMORY_RUNTIME
1381 );
1382 if (EFI_ERROR (Status)) {
1383 gBS->FreePool (mVariableModuleGlobal);
1384 gBS->FreePool (VolatileVariableStore);
1385 return EFI_UNSUPPORTED;
1386 }
1387 //
1388 // Get address of non volatile variable store base
1389 //
1390 mVariableModuleGlobal->VariableGlobal[Physical].NonVolatileVariableBase = VariableStoreEntry.Base;
1391
1392 //
1393 // Check Integrity
1394 //
1395 //
1396 // Find the Correct Instance of the FV Block Service.
1397 //
1398 Instance = 0;
1399 CurrPtr = (CHAR8 *) ((UINTN) mVariableModuleGlobal->VariableGlobal[Physical].NonVolatileVariableBase);
1400 while (EfiFvbGetPhysicalAddress (Instance, &FvVolHdr) == EFI_SUCCESS) {
1401 FwVolHeader = (EFI_FIRMWARE_VOLUME_HEADER *) ((UINTN) FvVolHdr);
1402 if (CurrPtr >= (CHAR8 *) FwVolHeader && CurrPtr < (((CHAR8 *) FwVolHeader) + FwVolHeader->FvLength)) {
1403 mVariableModuleGlobal->FvbInstance = Instance;
1404 break;
1405 }
1406
1407 Instance++;
1408 }
1409
1410 VariableStoreHeader = (VARIABLE_STORE_HEADER *) CurrPtr;
1411 if (GetVariableStoreStatus (VariableStoreHeader) == EfiValid) {
1412 if (~VariableStoreHeader->Size == 0) {
1413 Status = UpdateVariableStore (
1414 &mVariableModuleGlobal->VariableGlobal[Physical],
1415 FALSE,
1416 FALSE,
1417 mVariableModuleGlobal->FvbInstance,
1418 (UINTN) &VariableStoreHeader->Size,
1419 sizeof (UINT32),
1420 (UINT8 *) &VariableStoreEntry.Length
1421 );
1422
1423 if (EFI_ERROR (Status)) {
1424 return Status;
1425 }
1426 }
1427
1428 mVariableModuleGlobal->VariableGlobal[Physical].NonVolatileVariableBase = (EFI_PHYSICAL_ADDRESS) ((UINTN) CurrPtr);
1429 //
1430 // Parse non-volatile variable data and get last variable offset
1431 //
1432 NextVariable = (VARIABLE_HEADER *) (CurrPtr + sizeof (VARIABLE_STORE_HEADER));
1433 Status = EFI_SUCCESS;
1434
1435 while (IsValidVariableHeader (NextVariable)) {
1436 NextVariable = GetNextVariablePtr (NextVariable);
1437 }
1438
1439 mVariableModuleGlobal->NonVolatileLastVariableOffset = (UINTN) NextVariable - (UINTN) CurrPtr;
1440
1441 //
1442 // Check if the free area is blow a threshold
1443 //
1444 if ((((VARIABLE_STORE_HEADER *)((UINTN) CurrPtr))->Size - mVariableModuleGlobal->NonVolatileLastVariableOffset) < VARIABLE_RECLAIM_THRESHOLD) {
1445 Status = Reclaim (
1446 mVariableModuleGlobal->VariableGlobal[Physical].NonVolatileVariableBase,
1447 &mVariableModuleGlobal->NonVolatileLastVariableOffset,
1448 FALSE
1449 );
1450 }
1451
1452 if (EFI_ERROR (Status)) {
1453 gBS->FreePool (mVariableModuleGlobal);
1454 gBS->FreePool (VolatileVariableStore);
1455 return Status;
1456 }
1457
1458 //
1459 // Check if the free area is really free.
1460 //
1461 for (Index = mVariableModuleGlobal->NonVolatileLastVariableOffset; Index < VariableStoreHeader->Size; Index++) {
1462 Data = ((UINT8 *) (UINTN) mVariableModuleGlobal->VariableGlobal[Physical].NonVolatileVariableBase)[Index];
1463 if (Data != 0xff) {
1464 //
1465 // There must be something wrong in variable store, do reclaim operation.
1466 //
1467 Status = Reclaim (
1468 mVariableModuleGlobal->VariableGlobal[Physical].NonVolatileVariableBase,
1469 &mVariableModuleGlobal->NonVolatileLastVariableOffset,
1470 FALSE
1471 );
1472 break;
1473 }
1474 }
1475 }
1476
1477 if (EFI_ERROR (Status)) {
1478 gBS->FreePool (mVariableModuleGlobal);
1479 gBS->FreePool (VolatileVariableStore);
1480 }
1481
1482 return Status;
1483 }