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