1. Uefi2.1 feature - Add Hardware Error Record Persistence Support
[mirror_edk2.git] / MdeModulePkg / 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
23 #include "Variable.h"
24 #include <Guid/FlashMapHob.h>
25
26 //
27 // Don't use module globals after the SetVirtualAddress map is signaled
28 //
29 ESAL_VARIABLE_GLOBAL *mVariableModuleGlobal;
30
31 //
32 // This is a temperary function which will be removed
33 // when EfiAcquireLock in UefiLib can handle the
34 // the call in UEFI Runtimer driver in RT phase.
35 //
36 STATIC
37 VOID
38 AcquireLockOnlyAtBootTime (
39 IN EFI_LOCK *Lock
40 )
41 {
42 if (!EfiAtRuntime ()) {
43 EfiAcquireLock (Lock);
44 }
45 }
46
47 //
48 // This is a temperary function which will be removed
49 // when EfiAcquireLock in UefiLib can handle the
50 // the call in UEFI Runtimer driver in RT phase.
51 //
52 STATIC
53 VOID
54 ReleaseLockOnlyAtBootTime (
55 IN EFI_LOCK *Lock
56 )
57 {
58 if (!EfiAtRuntime ()) {
59 EfiReleaseLock (Lock);
60 }
61 }
62
63 STATIC
64 BOOLEAN
65 EFIAPI
66 IsValidVariableHeader (
67 IN VARIABLE_HEADER *Variable
68 )
69 /*++
70
71 Routine Description:
72
73 This code checks if variable header is valid or not.
74
75 Arguments:
76 Variable Pointer to the Variable Header.
77
78 Returns:
79 TRUE Variable header is valid.
80 FALSE Variable header is not valid.
81
82 --*/
83 {
84 if (Variable == NULL ||
85 Variable->StartId != VARIABLE_DATA ||
86 (sizeof (VARIABLE_HEADER) + Variable->NameSize + Variable->DataSize) > MAX_VARIABLE_SIZE
87 ) {
88 return FALSE;
89 }
90
91 return TRUE;
92 }
93
94 STATIC
95 EFI_STATUS
96 EFIAPI
97 UpdateVariableStore (
98 IN VARIABLE_GLOBAL *Global,
99 IN BOOLEAN Volatile,
100 IN BOOLEAN SetByIndex,
101 IN UINTN Instance,
102 IN UINTN DataPtrIndex,
103 IN UINT32 DataSize,
104 IN UINT8 *Buffer
105 )
106 /*++
107
108 Routine Description:
109
110 This function writes data to the FWH at the correct LBA even if the LBAs
111 are fragmented.
112
113 Arguments:
114
115 Global - Pointer to VARAIBLE_GLOBAL structure
116 Volatile - If the Variable is Volatile or Non-Volatile
117 SetByIndex - TRUE: Target pointer is given as index
118 FALSE: Target pointer is absolute
119 Instance - Instance of FV Block services
120 DataPtrIndex - Pointer to the Data from the end of VARIABLE_STORE_HEADER
121 structure
122 DataSize - Size of data to be written.
123 Buffer - Pointer to the buffer from which data is written
124
125 Returns:
126
127 EFI_INVALID_PARAMETER - Parameters not valid
128 EFI_SUCCESS - Variable store successfully updated
129
130 --*/
131 {
132 EFI_FV_BLOCK_MAP_ENTRY *PtrBlockMapEntry;
133 UINTN BlockIndex2;
134 UINTN LinearOffset;
135 UINTN CurrWriteSize;
136 UINTN CurrWritePtr;
137 UINT8 *CurrBuffer;
138 EFI_LBA LbaNumber;
139 UINTN Size;
140 EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader;
141 VARIABLE_STORE_HEADER *VolatileBase;
142 EFI_PHYSICAL_ADDRESS FvVolHdr;
143 EFI_PHYSICAL_ADDRESS DataPtr;
144 EFI_STATUS Status;
145
146 FwVolHeader = NULL;
147 DataPtr = DataPtrIndex;
148
149 //
150 // Check if the Data is Volatile
151 //
152 if (!Volatile) {
153 EfiFvbGetPhysicalAddress (Instance, &FvVolHdr);
154 FwVolHeader = (EFI_FIRMWARE_VOLUME_HEADER *) ((UINTN) FvVolHdr);
155 //
156 // Data Pointer should point to the actual Address where data is to be
157 // written
158 //
159 if (SetByIndex) {
160 DataPtr += Global->NonVolatileVariableBase;
161 }
162
163 if ((DataPtr + DataSize) >= ((EFI_PHYSICAL_ADDRESS) (UINTN) ((UINT8 *) FwVolHeader + FwVolHeader->FvLength))) {
164 return EFI_INVALID_PARAMETER;
165 }
166 } else {
167 //
168 // Data Pointer should point to the actual Address where data is to be
169 // written
170 //
171 VolatileBase = (VARIABLE_STORE_HEADER *) ((UINTN) Global->VolatileVariableBase);
172 if (SetByIndex) {
173 DataPtr += Global->VolatileVariableBase;
174 }
175
176 if ((DataPtr + DataSize) >= ((UINTN) ((UINT8 *) VolatileBase + VolatileBase->Size))) {
177 return EFI_INVALID_PARAMETER;
178 }
179
180 //
181 // If Volatile Variable just do a simple mem copy.
182 //
183 CopyMem ((UINT8 *)(UINTN)DataPtr, Buffer, DataSize);
184 return EFI_SUCCESS;
185 }
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->BlockMap; 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->Length)) {
207 if ((CurrWritePtr + CurrWriteSize) <= (LinearOffset + PtrBlockMapEntry->Length)) {
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->Length - 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->Length;
230 CurrBuffer = CurrBuffer + Size;
231 CurrWriteSize = CurrWriteSize - Size;
232 }
233 }
234
235 LinearOffset += PtrBlockMapEntry->Length;
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 GetNextVariablePtr (
316 IN VARIABLE_HEADER *Variable
317 )
318 /*++
319
320 Routine Description:
321
322 This code gets the pointer to the next variable header.
323
324 Arguments:
325
326 Variable Pointer to the Variable Header.
327
328 Returns:
329
330 VARIABLE_HEADER* Pointer to next variable header.
331
332 --*/
333 {
334 if (!IsValidVariableHeader (Variable)) {
335 return NULL;
336 }
337 //
338 // Be careful about pad size for alignment
339 //
340 return (VARIABLE_HEADER *) ((UINTN) GetVariableDataPtr (Variable) + Variable->DataSize + GET_PAD_SIZE (Variable->DataSize));
341 }
342
343 STATIC
344 VARIABLE_HEADER *
345 EFIAPI
346 GetEndPointer (
347 IN VARIABLE_STORE_HEADER *VarStoreHeader
348 )
349 /*++
350
351 Routine Description:
352
353 This code gets the pointer to the last variable memory pointer byte
354
355 Arguments:
356
357 VarStoreHeader Pointer to the Variable Store Header.
358
359 Returns:
360
361 VARIABLE_HEADER* Pointer to last unavailable Variable Header
362
363 --*/
364 {
365 //
366 // The end of variable store
367 //
368 return (VARIABLE_HEADER *) ((UINTN) VarStoreHeader + VarStoreHeader->Size);
369 }
370
371 STATIC
372 EFI_STATUS
373 EFIAPI
374 Reclaim (
375 IN EFI_PHYSICAL_ADDRESS VariableBase,
376 OUT UINTN *LastVariableOffset,
377 IN BOOLEAN IsVolatile
378 )
379 /*++
380
381 Routine Description:
382
383 Variable store garbage collection and reclaim operation
384
385 Arguments:
386
387 VariableBase Base address of variable store
388 LastVariableOffset Offset of last variable
389 IsVolatile The variable store is volatile or not,
390 if it is non-volatile, need FTW
391
392 Returns:
393
394 EFI STATUS
395
396 --*/
397 {
398 VARIABLE_HEADER *Variable;
399 VARIABLE_HEADER *NextVariable;
400 VARIABLE_STORE_HEADER *VariableStoreHeader;
401 UINT8 *ValidBuffer;
402 UINTN ValidBufferSize;
403 UINTN VariableSize;
404 UINT8 *CurrPtr;
405 EFI_STATUS Status;
406
407 VariableStoreHeader = (VARIABLE_STORE_HEADER *) ((UINTN) VariableBase);
408
409 //
410 // Start Pointers for the variable.
411 //
412 Variable = (VARIABLE_HEADER *) (VariableStoreHeader + 1);
413
414 ValidBufferSize = sizeof (VARIABLE_STORE_HEADER);
415
416 while (IsValidVariableHeader (Variable)) {
417 NextVariable = GetNextVariablePtr (Variable);
418 if (Variable->State == VAR_ADDED) {
419 VariableSize = (UINTN) NextVariable - (UINTN) Variable;
420 ValidBufferSize += VariableSize;
421 }
422
423 Variable = NextVariable;
424 }
425
426 ValidBuffer = AllocatePool (ValidBufferSize);
427 if (ValidBuffer == NULL) {
428 return EFI_OUT_OF_RESOURCES;
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 FreePool (ValidBuffer);
480
481 if (EFI_ERROR (Status)) {
482 *LastVariableOffset = 0;
483 }
484
485 return Status;
486 }
487
488 STATIC
489 EFI_STATUS
490 EFIAPI
491 FindVariable (
492 IN CHAR16 *VariableName,
493 IN EFI_GUID *VendorGuid,
494 OUT VARIABLE_POINTER_TRACK *PtrTrack,
495 IN VARIABLE_GLOBAL *Global
496 )
497 /*++
498
499 Routine Description:
500
501 This code finds variable in storage blocks (Volatile or Non-Volatile)
502
503 Arguments:
504
505 VariableName Name of the variable to be found
506 VendorGuid Vendor GUID to be found.
507 PtrTrack Variable Track Pointer structure that contains
508 Variable Information.
509 Contains the pointer of Variable header.
510 Global VARIABLE_GLOBAL pointer
511
512 Returns:
513
514 EFI STATUS
515
516 --*/
517 {
518 VARIABLE_HEADER *Variable[2];
519 VARIABLE_STORE_HEADER *VariableStoreHeader[2];
520 UINTN Index;
521
522 //
523 // We aquire the lock at the entry of FindVariable as GetVariable, GetNextVariableName
524 // SetVariable all call FindVariable at entry point. Please move "Aquire Lock" to
525 // the correct places if this assumption does not hold TRUE anymore.
526 //
527 AcquireLockOnlyAtBootTime(&Global->VariableServicesLock);
528
529 //
530 // 0: Non-Volatile, 1: Volatile
531 //
532 VariableStoreHeader[0] = (VARIABLE_STORE_HEADER *) ((UINTN) Global->NonVolatileVariableBase);
533 VariableStoreHeader[1] = (VARIABLE_STORE_HEADER *) ((UINTN) Global->VolatileVariableBase);
534
535 //
536 // Start Pointers for the variable.
537 // Actual Data Pointer where data can be written.
538 //
539 Variable[0] = (VARIABLE_HEADER *) (VariableStoreHeader[0] + 1);
540 Variable[1] = (VARIABLE_HEADER *) (VariableStoreHeader[1] + 1);
541
542 if (VariableName[0] != 0 && VendorGuid == NULL) {
543 return EFI_INVALID_PARAMETER;
544 }
545 //
546 // Find the variable by walk through non-volatile and volatile variable store
547 //
548 for (Index = 0; Index < 2; Index++) {
549 PtrTrack->StartPtr = (VARIABLE_HEADER *) (VariableStoreHeader[Index] + 1);
550 PtrTrack->EndPtr = GetEndPointer (VariableStoreHeader[Index]);
551
552 while (IsValidVariableHeader (Variable[Index]) && (Variable[Index] <= GetEndPointer (VariableStoreHeader[Index]))) {
553 if (Variable[Index]->State == VAR_ADDED) {
554 if (!EfiAtRuntime () || (Variable[Index]->Attributes & EFI_VARIABLE_RUNTIME_ACCESS)) {
555 if (VariableName[0] == 0) {
556 PtrTrack->CurrPtr = Variable[Index];
557 PtrTrack->Volatile = (BOOLEAN) Index;
558 return EFI_SUCCESS;
559 } else {
560 if (CompareGuid (VendorGuid, &Variable[Index]->VendorGuid)) {
561 if (!CompareMem (VariableName, GET_VARIABLE_NAME_PTR (Variable[Index]), Variable[Index]->NameSize)) {
562 PtrTrack->CurrPtr = Variable[Index];
563 PtrTrack->Volatile = (BOOLEAN) Index;
564 return EFI_SUCCESS;
565 }
566 }
567 }
568 }
569 }
570
571 Variable[Index] = GetNextVariablePtr (Variable[Index]);
572 }
573 //
574 // While (...)
575 //
576 }
577 //
578 // for (...)
579 //
580 PtrTrack->CurrPtr = NULL;
581 return EFI_NOT_FOUND;
582 }
583
584 EFI_STATUS
585 EFIAPI
586 GetVariable (
587 IN CHAR16 *VariableName,
588 IN EFI_GUID *VendorGuid,
589 OUT UINT32 *Attributes OPTIONAL,
590 IN OUT UINTN *DataSize,
591 OUT VOID *Data,
592 IN VARIABLE_GLOBAL *Global,
593 IN UINT32 Instance
594 )
595 /*++
596
597 Routine Description:
598
599 This code finds variable in storage blocks (Volatile or Non-Volatile)
600
601 Arguments:
602
603 VariableName Name of Variable to be found
604 VendorGuid Variable vendor GUID
605 Attributes OPTIONAL Attribute value of the variable found
606 DataSize Size of Data found. If size is less than the
607 data, this value contains the required size.
608 Data Data pointer
609 Global Pointer to VARIABLE_GLOBAL structure
610 Instance Instance of the Firmware Volume.
611
612 Returns:
613
614 EFI_INVALID_PARAMETER - Invalid parameter
615 EFI_SUCCESS - Find the specified variable
616 EFI_NOT_FOUND - Not found
617 EFI_BUFFER_TO_SMALL - DataSize is too small for the result
618
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_INVALID_PARAMETER - Invalid parameter
806 EFI_SUCCESS - Set successfully
807 EFI_OUT_OF_RESOURCES - Resource not enough to set variable
808 EFI_NOT_FOUND - Not found
809 EFI_DEVICE_ERROR - Variable can not be saved due to hardware failure
810 EFI_WRITE_PROTECTED - Variable is read-only
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 //
827 // Check input parameters
828 //
829 if (VariableName == NULL || VariableName[0] == 0 || VendorGuid == NULL) {
830 return EFI_INVALID_PARAMETER;
831 }
832 //
833 // Make sure if runtime bit is set, boot service bit is set also
834 //
835 if ((Attributes & (EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS)) == EFI_VARIABLE_RUNTIME_ACCESS) {
836 return EFI_INVALID_PARAMETER;
837 }
838 //
839 // The size of the VariableName, including the Unicode Null in bytes plus
840 // the DataSize is limited to maximum size of MAX_HARDWARE_ERROR_VARIABLE_SIZE (32K)
841 // bytes for HwErrRec, and MAX_VARIABLE_SIZE (1024) bytes for the others.
842 //
843 if ((Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == EFI_VARIABLE_HARDWARE_ERROR_RECORD) {
844 if ((DataSize > MAX_HARDWARE_ERROR_VARIABLE_SIZE) ||
845 (sizeof (VARIABLE_HEADER) + StrSize (VariableName) + DataSize > MAX_HARDWARE_ERROR_VARIABLE_SIZE)) {
846 return EFI_INVALID_PARAMETER;
847 }
848 } else {
849 //
850 // The size of the VariableName, including the Unicode Null in bytes plus
851 // the DataSize is limited to maximum size of MAX_VARIABLE_SIZE (1024) bytes.
852 //
853 if ((DataSize > MAX_VARIABLE_SIZE) ||
854 (sizeof (VARIABLE_HEADER) + StrSize (VariableName) + DataSize > MAX_VARIABLE_SIZE)) {
855 return EFI_INVALID_PARAMETER;
856 }
857 }
858 //
859 // Check whether the input variable is already existed
860 //
861
862 Status = FindVariable (VariableName, VendorGuid, &Variable, Global);
863
864 if (Status == EFI_SUCCESS && Variable.CurrPtr != NULL) {
865 //
866 // Update/Delete existing variable
867 //
868
869 if (EfiAtRuntime ()) {
870 //
871 // If EfiAtRuntime and the variable is Volatile and Runtime Access,
872 // the volatile is ReadOnly, and SetVariable should be aborted and
873 // return EFI_WRITE_PROTECTED.
874 //
875 if (Variable.Volatile) {
876 Status = EFI_WRITE_PROTECTED;
877 goto Done;
878 }
879 //
880 // Only variable have NV attribute can be updated/deleted in Runtime
881 //
882 if (!(Variable.CurrPtr->Attributes & EFI_VARIABLE_NON_VOLATILE)) {
883 Status = EFI_INVALID_PARAMETER;
884 goto Done;
885 }
886 }
887 //
888 // Setting a data variable with no access, or zero DataSize attributes
889 // specified causes it to be deleted.
890 //
891 if (DataSize == 0 || (Attributes & (EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS)) == 0) {
892 State = Variable.CurrPtr->State;
893 State &= VAR_DELETED;
894
895 Status = UpdateVariableStore (
896 Global,
897 Variable.Volatile,
898 FALSE,
899 Instance,
900 (UINTN) &Variable.CurrPtr->State,
901 sizeof (UINT8),
902 &State
903 );
904 goto Done;
905 }
906 //
907 // If the variable is marked valid and the same data has been passed in
908 // then return to the caller immediately.
909 //
910 if (Variable.CurrPtr->DataSize == DataSize &&
911 (CompareMem (Data, GetVariableDataPtr (Variable.CurrPtr), DataSize) == 0)) {
912 Status = EFI_SUCCESS;
913 goto Done;
914 } else if ((Variable.CurrPtr->State == VAR_ADDED) ||
915 (Variable.CurrPtr->State == (VAR_ADDED & VAR_IN_DELETED_TRANSITION))) {
916 //
917 // Mark the old variable as in delete transition
918 //
919 State = Variable.CurrPtr->State;
920 State &= VAR_IN_DELETED_TRANSITION;
921
922 Status = UpdateVariableStore (
923 Global,
924 Variable.Volatile,
925 FALSE,
926 Instance,
927 (UINTN) &Variable.CurrPtr->State,
928 sizeof (UINT8),
929 &State
930 );
931 if (EFI_ERROR (Status)) {
932 goto Done;
933 }
934 }
935 } else if (Status == EFI_NOT_FOUND) {
936 //
937 // Create a new variable
938 //
939
940 //
941 // Make sure we are trying to create a new variable.
942 // Setting a data variable with no access, or zero DataSize attributes means to delete it.
943 //
944 if (DataSize == 0 || (Attributes & (EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS)) == 0) {
945 Status = EFI_NOT_FOUND;
946 goto Done;
947 }
948
949 //
950 // Only variable have NV|RT attribute can be created in Runtime
951 //
952 if (EfiAtRuntime () &&
953 (!(Attributes & EFI_VARIABLE_RUNTIME_ACCESS) || !(Attributes & EFI_VARIABLE_NON_VOLATILE))) {
954 Status = EFI_INVALID_PARAMETER;
955 goto Done;
956 }
957 } else {
958 //
959 // Status should be EFI_INVALID_PARAMETER here according to return status of FindVariable().
960 //
961 ASSERT (Status == EFI_INVALID_PARAMETER);
962 goto Done;
963 }
964
965 //
966 // Function part - create a new variable and copy the data.
967 // Both update a variable and create a variable will come here.
968 //
969 // Tricky part: Use scratch data area at the end of volatile variable store
970 // as a temporary storage.
971 //
972 NextVariable = GetEndPointer ((VARIABLE_STORE_HEADER *) ((UINTN) Global->VolatileVariableBase));
973
974 SetMem (NextVariable, SCRATCH_SIZE, 0xff);
975
976 NextVariable->StartId = VARIABLE_DATA;
977 NextVariable->Attributes = Attributes;
978 //
979 // NextVariable->State = VAR_ADDED;
980 //
981 NextVariable->Reserved = 0;
982 VarNameOffset = sizeof (VARIABLE_HEADER);
983 VarNameSize = StrSize (VariableName);
984 CopyMem (
985 (UINT8 *) ((UINTN) NextVariable + VarNameOffset),
986 VariableName,
987 VarNameSize
988 );
989 VarDataOffset = VarNameOffset + VarNameSize + GET_PAD_SIZE (VarNameSize);
990 CopyMem (
991 (UINT8 *) ((UINTN) NextVariable + VarDataOffset),
992 Data,
993 DataSize
994 );
995 CopyMem (&NextVariable->VendorGuid, VendorGuid, sizeof (EFI_GUID));
996 //
997 // There will be pad bytes after Data, the NextVariable->NameSize and
998 // NextVariable->DataSize should not include pad size so that variable
999 // service can get actual size in GetVariable
1000 //
1001 NextVariable->NameSize = (UINT32)VarNameSize;
1002 NextVariable->DataSize = (UINT32)DataSize;
1003
1004 //
1005 // The actual size of the variable that stores in storage should
1006 // include pad size.
1007 //
1008 VarSize = VarDataOffset + DataSize + GET_PAD_SIZE (DataSize);
1009 if (Attributes & EFI_VARIABLE_NON_VOLATILE) {
1010 //
1011 // Create a nonvolatile variable
1012 //
1013
1014 if ((UINT32) (VarSize +*NonVolatileOffset) >
1015 ((VARIABLE_STORE_HEADER *) ((UINTN) (Global->NonVolatileVariableBase)))->Size
1016 ) {
1017 if (EfiAtRuntime ()) {
1018 Status = EFI_OUT_OF_RESOURCES;
1019 goto Done;
1020 }
1021 //
1022 // Perform garbage collection & reclaim operation
1023 //
1024 Status = Reclaim (Global->NonVolatileVariableBase, NonVolatileOffset, FALSE);
1025 if (EFI_ERROR (Status)) {
1026 goto Done;
1027 }
1028 //
1029 // If still no enough space, return out of resources
1030 //
1031 if ((UINT32) (VarSize +*NonVolatileOffset) >
1032 ((VARIABLE_STORE_HEADER *) ((UINTN) (Global->NonVolatileVariableBase)))->Size
1033 ) {
1034 Status = EFI_OUT_OF_RESOURCES;
1035 goto Done;
1036 }
1037
1038 Reclaimed = TRUE;
1039 }
1040 //
1041 // Three steps
1042 // 1. Write variable header
1043 // 2. Write variable data
1044 // 3. Set variable state to valid
1045 //
1046 //
1047 // Step 1:
1048 //
1049 Status = UpdateVariableStore (
1050 Global,
1051 FALSE,
1052 TRUE,
1053 Instance,
1054 *NonVolatileOffset,
1055 sizeof (VARIABLE_HEADER),
1056 (UINT8 *) NextVariable
1057 );
1058
1059 if (EFI_ERROR (Status)) {
1060 goto Done;
1061 }
1062 //
1063 // Step 2:
1064 //
1065 Status = UpdateVariableStore (
1066 Global,
1067 FALSE,
1068 TRUE,
1069 Instance,
1070 *NonVolatileOffset + sizeof (VARIABLE_HEADER),
1071 (UINT32) VarSize - sizeof (VARIABLE_HEADER),
1072 (UINT8 *) NextVariable + sizeof (VARIABLE_HEADER)
1073 );
1074
1075 if (EFI_ERROR (Status)) {
1076 goto Done;
1077 }
1078 //
1079 // Step 3:
1080 //
1081 NextVariable->State = VAR_ADDED;
1082 Status = UpdateVariableStore (
1083 Global,
1084 FALSE,
1085 TRUE,
1086 Instance,
1087 *NonVolatileOffset,
1088 sizeof (VARIABLE_HEADER),
1089 (UINT8 *) NextVariable
1090 );
1091
1092 if (EFI_ERROR (Status)) {
1093 goto Done;
1094 }
1095
1096 *NonVolatileOffset = *NonVolatileOffset + VarSize;
1097
1098 } else {
1099 //
1100 // Create a volatile variable
1101 //
1102
1103 if ((UINT32) (VarSize +*VolatileOffset) >
1104 ((VARIABLE_STORE_HEADER *) ((UINTN) (Global->VolatileVariableBase)))->Size) {
1105 //
1106 // Perform garbage collection & reclaim operation
1107 //
1108 Status = Reclaim (Global->VolatileVariableBase, VolatileOffset, TRUE);
1109 if (EFI_ERROR (Status)) {
1110 goto Done;
1111 }
1112 //
1113 // If still no enough space, return out of resources
1114 //
1115 if ((UINT32) (VarSize +*VolatileOffset) >
1116 ((VARIABLE_STORE_HEADER *) ((UINTN) (Global->VolatileVariableBase)))->Size
1117 ) {
1118 Status = EFI_OUT_OF_RESOURCES;
1119 goto Done;
1120 }
1121
1122 Reclaimed = TRUE;
1123 }
1124
1125 NextVariable->State = VAR_ADDED;
1126 Status = UpdateVariableStore (
1127 Global,
1128 TRUE,
1129 TRUE,
1130 Instance,
1131 *VolatileOffset,
1132 (UINT32) VarSize,
1133 (UINT8 *) NextVariable
1134 );
1135
1136 if (EFI_ERROR (Status)) {
1137 goto Done;
1138 }
1139
1140 *VolatileOffset = *VolatileOffset + VarSize;
1141 }
1142 //
1143 // Mark the old variable as deleted
1144 //
1145 if (!Reclaimed && !EFI_ERROR (Status) && Variable.CurrPtr != NULL) {
1146 State = Variable.CurrPtr->State;
1147 State &= VAR_DELETED;
1148
1149 Status = UpdateVariableStore (
1150 Global,
1151 Variable.Volatile,
1152 FALSE,
1153 Instance,
1154 (UINTN) &Variable.CurrPtr->State,
1155 sizeof (UINT8),
1156 &State
1157 );
1158 goto Done;
1159 }
1160
1161 Status = EFI_SUCCESS;
1162 Done:
1163 ReleaseLockOnlyAtBootTime (&Global->VariableServicesLock);
1164 return Status;
1165 }
1166
1167 EFI_STATUS
1168 EFIAPI
1169 QueryVariableInfo (
1170 IN UINT32 Attributes,
1171 OUT UINT64 *MaximumVariableStorageSize,
1172 OUT UINT64 *RemainingVariableStorageSize,
1173 OUT UINT64 *MaximumVariableSize,
1174 IN VARIABLE_GLOBAL *Global,
1175 IN UINT32 Instance
1176 )
1177 /*++
1178
1179 Routine Description:
1180
1181 This code returns information about the EFI variables.
1182
1183 Arguments:
1184
1185 Attributes Attributes bitmask to specify the type of variables
1186 on which to return information.
1187 MaximumVariableStorageSize Pointer to the maximum size of the storage space available
1188 for the EFI variables associated with the attributes specified.
1189 RemainingVariableStorageSize Pointer to the remaining size of the storage space available
1190 for EFI variables associated with the attributes specified.
1191 MaximumVariableSize Pointer to the maximum size of an individual EFI variables
1192 associated with the attributes specified.
1193 Global Pointer to VARIABLE_GLOBAL structure.
1194 Instance Instance of the Firmware Volume.
1195
1196 Returns:
1197
1198 EFI STATUS
1199 EFI_INVALID_PARAMETER - An invalid combination of attribute bits was supplied.
1200 EFI_SUCCESS - Query successfully.
1201 EFI_UNSUPPORTED - The attribute is not supported on this platform.
1202
1203 --*/
1204 {
1205 VARIABLE_HEADER *Variable;
1206 VARIABLE_HEADER *NextVariable;
1207 UINT64 VariableSize;
1208 VARIABLE_STORE_HEADER *VariableStoreHeader;
1209
1210 if(MaximumVariableStorageSize == NULL || RemainingVariableStorageSize == NULL || MaximumVariableSize == NULL || Attributes == 0) {
1211 return EFI_INVALID_PARAMETER;
1212 }
1213
1214 if((Attributes & (EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_HARDWARE_ERROR_RECORD)) == 0) {
1215 //
1216 // Make sure the Attributes combination is supported by the platform.
1217 //
1218 return EFI_UNSUPPORTED;
1219 } else if ((Attributes & (EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS)) == EFI_VARIABLE_RUNTIME_ACCESS) {
1220 //
1221 // Make sure if runtime bit is set, boot service bit is set also.
1222 //
1223 return EFI_INVALID_PARAMETER;
1224 } else if (EfiAtRuntime () && !(Attributes & EFI_VARIABLE_RUNTIME_ACCESS)) {
1225 //
1226 // Make sure RT Attribute is set if we are in Runtime phase.
1227 //
1228 return EFI_INVALID_PARAMETER;
1229 }
1230
1231 AcquireLockOnlyAtBootTime(&Global->VariableServicesLock);
1232
1233 if((Attributes & EFI_VARIABLE_NON_VOLATILE) == 0) {
1234 //
1235 // Query is Volatile related.
1236 //
1237 VariableStoreHeader = (VARIABLE_STORE_HEADER *) ((UINTN) Global->VolatileVariableBase);
1238 } else {
1239 //
1240 // Query is Non-Volatile related.
1241 //
1242 VariableStoreHeader = (VARIABLE_STORE_HEADER *) ((UINTN) Global->NonVolatileVariableBase);
1243 }
1244
1245 //
1246 // Now let's fill *MaximumVariableStorageSize *RemainingVariableStorageSize
1247 // with the storage size (excluding the storage header size).
1248 //
1249 *MaximumVariableStorageSize = VariableStoreHeader->Size - sizeof (VARIABLE_STORE_HEADER);
1250 *RemainingVariableStorageSize = VariableStoreHeader->Size - sizeof (VARIABLE_STORE_HEADER);
1251
1252 //
1253 // Let *MaximumVariableSize be MAX_VARIABLE_SIZE with the exception of the variable header size.
1254 //
1255 *MaximumVariableSize = MAX_VARIABLE_SIZE - sizeof (VARIABLE_HEADER);
1256
1257 //
1258 // Harware error record variable needs larger size.
1259 //
1260 if ((Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == EFI_VARIABLE_HARDWARE_ERROR_RECORD) {
1261 *MaximumVariableSize = MAX_HARDWARE_ERROR_VARIABLE_SIZE - sizeof (VARIABLE_HEADER);
1262 }
1263
1264 //
1265 // Point to the starting address of the variables.
1266 //
1267 Variable = (VARIABLE_HEADER *) (VariableStoreHeader + 1);
1268
1269 //
1270 // Now walk through the related variable store.
1271 //
1272 while (IsValidVariableHeader (Variable) && (Variable < GetEndPointer (VariableStoreHeader))) {
1273 NextVariable = GetNextVariablePtr (Variable);
1274 VariableSize = (UINT64) (UINTN) NextVariable - (UINT64) (UINTN) Variable;
1275
1276 if (EfiAtRuntime ()) {
1277 //
1278 // we don't take the state of the variables in mind
1279 // when calculating RemainingVariableStorageSize,
1280 // since the space occupied by variables not marked with
1281 // VAR_ADDED is not allowed to be reclaimed in Runtime.
1282 //
1283 *RemainingVariableStorageSize -= VariableSize;
1284 } else {
1285 //
1286 // Only care about Variables with State VAR_ADDED,because
1287 // the space not marked as VAR_ADDED is reclaimable now.
1288 //
1289 if (Variable->State == VAR_ADDED) {
1290 *RemainingVariableStorageSize -= VariableSize;
1291 }
1292 }
1293
1294 //
1295 // Go to the next one
1296 //
1297 Variable = NextVariable;
1298 }
1299
1300 if (*RemainingVariableStorageSize < sizeof (VARIABLE_HEADER)) {
1301 *MaximumVariableSize = 0;
1302 } else if ((*RemainingVariableStorageSize - sizeof (VARIABLE_HEADER)) < *MaximumVariableSize) {
1303 *MaximumVariableSize = *RemainingVariableStorageSize - sizeof (VARIABLE_HEADER);
1304 }
1305
1306 ReleaseLockOnlyAtBootTime (&Global->VariableServicesLock);
1307 return EFI_SUCCESS;
1308 }
1309
1310 EFI_STATUS
1311 EFIAPI
1312 VariableCommonInitialize (
1313 IN EFI_HANDLE ImageHandle,
1314 IN EFI_SYSTEM_TABLE *SystemTable
1315 )
1316 /*++
1317
1318 Routine Description:
1319 This function does common initialization for variable services
1320
1321 Arguments:
1322
1323 ImageHandle - The firmware allocated handle for the EFI image.
1324 SystemTable - A pointer to the EFI System Table.
1325
1326 Returns:
1327
1328 Status code.
1329
1330 EFI_NOT_FOUND - Variable store area not found.
1331 EFI_UNSUPPORTED - Currently only one non-volatile variable store is supported.
1332 EFI_SUCCESS - Variable services successfully initialized.
1333
1334 --*/
1335 {
1336 EFI_STATUS Status;
1337 EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader;
1338 CHAR8 *CurrPtr;
1339 VARIABLE_STORE_HEADER *VolatileVariableStore;
1340 VARIABLE_STORE_HEADER *VariableStoreHeader;
1341 VARIABLE_HEADER *NextVariable;
1342 UINT32 Instance;
1343 EFI_PHYSICAL_ADDRESS FvVolHdr;
1344 UINT64 TempVariableStoreHeader;
1345 EFI_GCD_MEMORY_SPACE_DESCRIPTOR GcdDescriptor;
1346 EFI_FLASH_SUBAREA_ENTRY VariableStoreEntry;
1347 UINT64 BaseAddress;
1348 UINT64 Length;
1349 UINTN Index;
1350 UINT8 Data;
1351
1352 mVariableModuleGlobal = AllocateRuntimePool (sizeof (ESAL_VARIABLE_GLOBAL));
1353 if (mVariableModuleGlobal == NULL) {
1354 return EFI_OUT_OF_RESOURCES;
1355 }
1356
1357 EfiInitializeLock(&mVariableModuleGlobal->VariableGlobal[Physical].VariableServicesLock, TPL_NOTIFY);
1358
1359 //
1360 // Allocate memory for volatile variable store
1361 //
1362 VolatileVariableStore = AllocateRuntimePool (VARIABLE_STORE_SIZE + SCRATCH_SIZE);
1363 if (VolatileVariableStore == NULL) {
1364 FreePool (mVariableModuleGlobal);
1365 return EFI_OUT_OF_RESOURCES;
1366 }
1367
1368 SetMem (VolatileVariableStore, VARIABLE_STORE_SIZE + SCRATCH_SIZE, 0xff);
1369
1370 //
1371 // Variable Specific Data
1372 //
1373 mVariableModuleGlobal->VariableGlobal[Physical].VolatileVariableBase = (EFI_PHYSICAL_ADDRESS) (UINTN) VolatileVariableStore;
1374 mVariableModuleGlobal->VolatileLastVariableOffset = sizeof (VARIABLE_STORE_HEADER);
1375
1376 VolatileVariableStore->Signature = VARIABLE_STORE_SIGNATURE;
1377 VolatileVariableStore->Size = VARIABLE_STORE_SIZE;
1378 VolatileVariableStore->Format = VARIABLE_STORE_FORMATTED;
1379 VolatileVariableStore->State = VARIABLE_STORE_HEALTHY;
1380 VolatileVariableStore->Reserved = 0;
1381 VolatileVariableStore->Reserved1 = 0;
1382
1383 //
1384 // Get non volatile varaible store
1385 //
1386
1387 TempVariableStoreHeader = (UINT64) PcdGet32 (PcdFlashNvStorageVariableBase);
1388 VariableStoreEntry.Base = TempVariableStoreHeader + \
1389 (((EFI_FIRMWARE_VOLUME_HEADER *) (UINTN) (TempVariableStoreHeader)) -> HeaderLength);
1390 VariableStoreEntry.Length = (UINT64) PcdGet32 (PcdFlashNvStorageVariableSize) - \
1391 (((EFI_FIRMWARE_VOLUME_HEADER *) (UINTN) (TempVariableStoreHeader)) -> HeaderLength);
1392 //
1393 // Mark the variable storage region of the FLASH as RUNTIME
1394 //
1395 BaseAddress = VariableStoreEntry.Base & (~EFI_PAGE_MASK);
1396 Length = VariableStoreEntry.Length + (VariableStoreEntry.Base - BaseAddress);
1397 Length = (Length + EFI_PAGE_SIZE - 1) & (~EFI_PAGE_MASK);
1398
1399 Status = gDS->GetMemorySpaceDescriptor (BaseAddress, &GcdDescriptor);
1400 if (EFI_ERROR (Status)) {
1401 FreePool (mVariableModuleGlobal);
1402 FreePool (VolatileVariableStore);
1403 return EFI_UNSUPPORTED;
1404 }
1405
1406 Status = gDS->SetMemorySpaceAttributes (
1407 BaseAddress,
1408 Length,
1409 GcdDescriptor.Attributes | EFI_MEMORY_RUNTIME
1410 );
1411 if (EFI_ERROR (Status)) {
1412 FreePool (mVariableModuleGlobal);
1413 FreePool (VolatileVariableStore);
1414 return EFI_UNSUPPORTED;
1415 }
1416 //
1417 // Get address of non volatile variable store base
1418 //
1419 mVariableModuleGlobal->VariableGlobal[Physical].NonVolatileVariableBase = VariableStoreEntry.Base;
1420
1421 //
1422 // Check Integrity
1423 //
1424 //
1425 // Find the Correct Instance of the FV Block Service.
1426 //
1427 Instance = 0;
1428 CurrPtr = (CHAR8 *) ((UINTN) mVariableModuleGlobal->VariableGlobal[Physical].NonVolatileVariableBase);
1429 while (EfiFvbGetPhysicalAddress (Instance, &FvVolHdr) == EFI_SUCCESS) {
1430 FwVolHeader = (EFI_FIRMWARE_VOLUME_HEADER *) ((UINTN) FvVolHdr);
1431 if (CurrPtr >= (CHAR8 *) FwVolHeader && CurrPtr < (((CHAR8 *) FwVolHeader) + FwVolHeader->FvLength)) {
1432 mVariableModuleGlobal->FvbInstance = Instance;
1433 break;
1434 }
1435
1436 Instance++;
1437 }
1438
1439 VariableStoreHeader = (VARIABLE_STORE_HEADER *) CurrPtr;
1440 if (GetVariableStoreStatus (VariableStoreHeader) == EfiValid) {
1441 if (~VariableStoreHeader->Size == 0) {
1442 Status = UpdateVariableStore (
1443 &mVariableModuleGlobal->VariableGlobal[Physical],
1444 FALSE,
1445 FALSE,
1446 mVariableModuleGlobal->FvbInstance,
1447 (UINTN) &VariableStoreHeader->Size,
1448 sizeof (UINT32),
1449 (UINT8 *) &VariableStoreEntry.Length
1450 );
1451 //
1452 // As Variables are stored in NV storage, which are slow devices,such as flash.
1453 // Variable operation may skip checking variable program result to improve performance,
1454 // We can assume Variable program is OK through some check point.
1455 // Variable Store Size Setting should be the first Variable write operation,
1456 // We can assume all Read/Write is OK if we can set Variable store size successfully.
1457 // If write fail, we will assert here
1458 //
1459 ASSERT(VariableStoreHeader->Size == VariableStoreEntry.Length);
1460
1461 if (EFI_ERROR (Status)) {
1462 return Status;
1463 }
1464 }
1465
1466 mVariableModuleGlobal->VariableGlobal[Physical].NonVolatileVariableBase = (EFI_PHYSICAL_ADDRESS) ((UINTN) CurrPtr);
1467 //
1468 // Parse non-volatile variable data and get last variable offset
1469 //
1470 NextVariable = (VARIABLE_HEADER *) (CurrPtr + sizeof (VARIABLE_STORE_HEADER));
1471 Status = EFI_SUCCESS;
1472
1473 while (IsValidVariableHeader (NextVariable)) {
1474 NextVariable = GetNextVariablePtr (NextVariable);
1475 }
1476
1477 mVariableModuleGlobal->NonVolatileLastVariableOffset = (UINTN) NextVariable - (UINTN) CurrPtr;
1478
1479 //
1480 // Check if the free area is blow a threshold
1481 //
1482 if ((((VARIABLE_STORE_HEADER *)((UINTN) CurrPtr))->Size - mVariableModuleGlobal->NonVolatileLastVariableOffset) < VARIABLE_RECLAIM_THRESHOLD) {
1483 Status = Reclaim (
1484 mVariableModuleGlobal->VariableGlobal[Physical].NonVolatileVariableBase,
1485 &mVariableModuleGlobal->NonVolatileLastVariableOffset,
1486 FALSE
1487 );
1488 }
1489
1490 if (EFI_ERROR (Status)) {
1491 FreePool (mVariableModuleGlobal);
1492 FreePool (VolatileVariableStore);
1493 return Status;
1494 }
1495
1496 //
1497 // Check if the free area is really free.
1498 //
1499 for (Index = mVariableModuleGlobal->NonVolatileLastVariableOffset; Index < VariableStoreHeader->Size; Index++) {
1500 Data = ((UINT8 *) (UINTN) mVariableModuleGlobal->VariableGlobal[Physical].NonVolatileVariableBase)[Index];
1501 if (Data != 0xff) {
1502 //
1503 // There must be something wrong in variable store, do reclaim operation.
1504 //
1505 Status = Reclaim (
1506 mVariableModuleGlobal->VariableGlobal[Physical].NonVolatileVariableBase,
1507 &mVariableModuleGlobal->NonVolatileLastVariableOffset,
1508 FALSE
1509 );
1510 break;
1511 }
1512 }
1513 }
1514
1515 if (EFI_ERROR (Status)) {
1516 FreePool (mVariableModuleGlobal);
1517 FreePool (VolatileVariableStore);
1518 }
1519
1520 return Status;
1521 }