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