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