]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Universal/Variable/RuntimeDxe/Variable.c
bc4e6eb38d0d29a94cc365391bd0ede4e5ef3c5f
[mirror_edk2.git] / MdeModulePkg / Universal / Variable / RuntimeDxe / Variable.c
1 /** @file
2
3 Implement all four UEFI Runtime Variable services for the nonvolatile
4 and volatile storage space and install variable architecture protocol.
5
6 Copyright (c) 2006 - 2008, Intel Corporation
7 All rights reserved. This program and the accompanying materials
8 are licensed and made available under the terms and conditions of the BSD License
9 which accompanies this distribution. The full text of the license may be found at
10 http://opensource.org/licenses/bsd-license.php
11
12 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
13 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
14
15 **/
16
17
18 #include "Variable.h"
19
20 VARIABLE_MODULE_GLOBAL *mVariableModuleGlobal;
21 EFI_EVENT mVirtualAddressChangeEvent = NULL;
22 EFI_HANDLE mHandle = NULL;
23
24
25 //
26 // This is a temperary function which will be removed
27 // when EfiAcquireLock in UefiLib can handle the
28 // the call in UEFI Runtimer driver in RT phase.
29 //
30 VOID
31 AcquireLockOnlyAtBootTime (
32 IN EFI_LOCK *Lock
33 )
34 {
35 if (!EfiAtRuntime ()) {
36 EfiAcquireLock (Lock);
37 }
38 }
39
40 //
41 // This is a temperary function which will be removed
42 // when EfiAcquireLock in UefiLib can handle the
43 // the call in UEFI Runtimer driver in RT phase.
44 //
45 VOID
46 ReleaseLockOnlyAtBootTime (
47 IN EFI_LOCK *Lock
48 )
49 {
50 if (!EfiAtRuntime ()) {
51 EfiReleaseLock (Lock);
52 }
53 }
54
55
56 GLOBAL_REMOVE_IF_UNREFERENCED VARIABLE_INFO_ENTRY *gVariableInfo = NULL;
57
58
59 /**
60 Routine used to track statistical information about variable usage.
61 The data is stored in the EFI system table so it can be accessed later.
62 VariableInfo.efi can dump out the table. Only Boot Services variable
63 accesses are tracked by this code. The PcdVariableCollectStatistics
64 build flag controls if this feature is enabled.
65
66 A read that hits in the cache will have Read and Cache true for
67 the transaction. Data is allocated by this routine, but never
68 freed.
69
70 @param[in] VariableName Name of the Variable to track
71 @param[in] VendorGuid Guid of the Variable to track
72 @param[in] Volatile TRUE if volatile FALSE if non-volatile
73 @param[in] Read TRUE if GetVariable() was called
74 @param[in] Write TRUE if SetVariable() was called
75 @param[in] Delete TRUE if deleted via SetVariable()
76 @param[in] Cache TRUE for a cache hit.
77
78 **/
79 VOID
80 UpdateVariableInfo (
81 IN CHAR16 *VariableName,
82 IN EFI_GUID *VendorGuid,
83 IN BOOLEAN Volatile,
84 IN BOOLEAN Read,
85 IN BOOLEAN Write,
86 IN BOOLEAN Delete,
87 IN BOOLEAN Cache
88 )
89 {
90 VARIABLE_INFO_ENTRY *Entry;
91
92 if (FeaturePcdGet (PcdVariableCollectStatistics)) {
93
94 if (EfiAtRuntime ()) {
95 // Don't collect statistics at runtime
96 return;
97 }
98
99 if (gVariableInfo == NULL) {
100 //
101 // on the first call allocate a entry and place a pointer to it in
102 // the EFI System Table
103 //
104 gVariableInfo = AllocateZeroPool (sizeof (VARIABLE_INFO_ENTRY));
105 ASSERT (gVariableInfo != NULL);
106
107 CopyGuid (&gVariableInfo->VendorGuid, VendorGuid);
108 gVariableInfo->Name = AllocatePool (StrLen (VariableName));
109 StrCpy (gVariableInfo->Name, VariableName);
110 gVariableInfo->Volatile = Volatile;
111
112 gBS->InstallConfigurationTable (&gEfiVariableInfoGuid, gVariableInfo);
113 }
114
115
116 for (Entry = gVariableInfo; Entry != NULL; Entry = Entry->Next) {
117 if (CompareGuid (VendorGuid, &Entry->VendorGuid)) {
118 if (StrCmp (VariableName, Entry->Name) == 0) {
119 if (Read) {
120 Entry->ReadCount++;
121 }
122 if (Write) {
123 Entry->WriteCount++;
124 }
125 if (Delete) {
126 Entry->DeleteCount++;
127 }
128 if (Cache) {
129 Entry->CacheCount++;
130 }
131
132 return;
133 }
134 }
135
136 if (Entry->Next == NULL) {
137 //
138 // If the entry is not in the table add it.
139 // Next iteration of the loop will fill in the data
140 //
141 Entry->Next = AllocateZeroPool (sizeof (VARIABLE_INFO_ENTRY));
142 ASSERT (Entry->Next != NULL);
143
144 CopyGuid (&Entry->Next->VendorGuid, VendorGuid);
145 Entry->Next->Name = AllocatePool (StrLen (VariableName));
146 StrCpy (Entry->Next->Name, VariableName);
147 Entry->Next->Volatile = Volatile;
148 }
149
150 }
151 }
152 }
153
154
155 BOOLEAN
156 IsValidVariableHeader (
157 IN VARIABLE_HEADER *Variable
158 )
159 /*++
160
161 Routine Description:
162
163 This code checks if variable header is valid or not.
164
165 Arguments:
166 Variable Pointer to the Variable Header.
167
168 Returns:
169 TRUE Variable header is valid.
170 FALSE Variable header is not valid.
171
172 --*/
173 {
174 if (Variable == NULL || Variable->StartId != VARIABLE_DATA) {
175 return FALSE;
176 }
177
178 return TRUE;
179 }
180
181
182 EFI_STATUS
183 UpdateVariableStore (
184 IN VARIABLE_GLOBAL *Global,
185 IN BOOLEAN Volatile,
186 IN BOOLEAN SetByIndex,
187 IN UINTN Instance,
188 IN UINTN DataPtrIndex,
189 IN UINT32 DataSize,
190 IN UINT8 *Buffer
191 )
192 /*++
193
194 Routine Description:
195
196 This function writes data to the FWH at the correct LBA even if the LBAs
197 are fragmented.
198
199 Arguments:
200
201 Global - Pointer to VARAIBLE_GLOBAL structure
202 Volatile - If the Variable is Volatile or Non-Volatile
203 SetByIndex - TRUE: Target pointer is given as index
204 FALSE: Target pointer is absolute
205 Instance - Instance of FV Block services
206 DataPtrIndex - Pointer to the Data from the end of VARIABLE_STORE_HEADER
207 structure
208 DataSize - Size of data to be written.
209 Buffer - Pointer to the buffer from which data is written
210
211 Returns:
212
213 EFI_INVALID_PARAMETER - Parameters not valid
214 EFI_SUCCESS - Variable store successfully updated
215
216 --*/
217 {
218 EFI_FV_BLOCK_MAP_ENTRY *PtrBlockMapEntry;
219 UINTN BlockIndex2;
220 UINTN LinearOffset;
221 UINTN CurrWriteSize;
222 UINTN CurrWritePtr;
223 UINT8 *CurrBuffer;
224 EFI_LBA LbaNumber;
225 UINTN Size;
226 EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader;
227 VARIABLE_STORE_HEADER *VolatileBase;
228 EFI_PHYSICAL_ADDRESS FvVolHdr;
229 EFI_PHYSICAL_ADDRESS DataPtr;
230 EFI_STATUS Status;
231
232 FwVolHeader = NULL;
233 DataPtr = DataPtrIndex;
234
235 //
236 // Check if the Data is Volatile
237 //
238 if (!Volatile) {
239 EfiFvbGetPhysicalAddress (Instance, &FvVolHdr);
240 FwVolHeader = (EFI_FIRMWARE_VOLUME_HEADER *) ((UINTN) FvVolHdr);
241 //
242 // Data Pointer should point to the actual Address where data is to be
243 // written
244 //
245 if (SetByIndex) {
246 DataPtr += mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase;
247 }
248
249 if ((DataPtr + DataSize) >= ((EFI_PHYSICAL_ADDRESS) (UINTN) ((UINT8 *) FwVolHeader + FwVolHeader->FvLength))) {
250 return EFI_INVALID_PARAMETER;
251 }
252 } else {
253 //
254 // Data Pointer should point to the actual Address where data is to be
255 // written
256 //
257 VolatileBase = (VARIABLE_STORE_HEADER *) ((UINTN) mVariableModuleGlobal->VariableGlobal.VolatileVariableBase);
258 if (SetByIndex) {
259 DataPtr += mVariableModuleGlobal->VariableGlobal.VolatileVariableBase;
260 }
261
262 if ((DataPtr + DataSize) >= ((UINTN) ((UINT8 *) VolatileBase + VolatileBase->Size))) {
263 return EFI_INVALID_PARAMETER;
264 }
265
266 //
267 // If Volatile Variable just do a simple mem copy.
268 //
269 CopyMem ((UINT8 *)(UINTN)DataPtr, Buffer, DataSize);
270 return EFI_SUCCESS;
271 }
272
273 //
274 // If we are here we are dealing with Non-Volatile Variables
275 //
276 LinearOffset = (UINTN) FwVolHeader;
277 CurrWritePtr = (UINTN) DataPtr;
278 CurrWriteSize = DataSize;
279 CurrBuffer = Buffer;
280 LbaNumber = 0;
281
282 if (CurrWritePtr < LinearOffset) {
283 return EFI_INVALID_PARAMETER;
284 }
285
286 for (PtrBlockMapEntry = FwVolHeader->BlockMap; PtrBlockMapEntry->NumBlocks != 0; PtrBlockMapEntry++) {
287 for (BlockIndex2 = 0; BlockIndex2 < PtrBlockMapEntry->NumBlocks; BlockIndex2++) {
288 //
289 // Check to see if the Variable Writes are spanning through multiple
290 // blocks.
291 //
292 if ((CurrWritePtr >= LinearOffset) && (CurrWritePtr < LinearOffset + PtrBlockMapEntry->Length)) {
293 if ((CurrWritePtr + CurrWriteSize) <= (LinearOffset + PtrBlockMapEntry->Length)) {
294 Status = EfiFvbWriteBlock (
295 Instance,
296 LbaNumber,
297 (UINTN) (CurrWritePtr - LinearOffset),
298 &CurrWriteSize,
299 CurrBuffer
300 );
301 return Status;
302 } else {
303 Size = (UINT32) (LinearOffset + PtrBlockMapEntry->Length - CurrWritePtr);
304 Status = EfiFvbWriteBlock (
305 Instance,
306 LbaNumber,
307 (UINTN) (CurrWritePtr - LinearOffset),
308 &Size,
309 CurrBuffer
310 );
311 if (EFI_ERROR (Status)) {
312 return Status;
313 }
314
315 CurrWritePtr = LinearOffset + PtrBlockMapEntry->Length;
316 CurrBuffer = CurrBuffer + Size;
317 CurrWriteSize = CurrWriteSize - Size;
318 }
319 }
320
321 LinearOffset += PtrBlockMapEntry->Length;
322 LbaNumber++;
323 }
324 }
325
326 return EFI_SUCCESS;
327 }
328
329
330 VARIABLE_STORE_STATUS
331 GetVariableStoreStatus (
332 IN VARIABLE_STORE_HEADER *VarStoreHeader
333 )
334 /*++
335
336 Routine Description:
337
338 This code gets the current status of Variable Store.
339
340 Arguments:
341
342 VarStoreHeader Pointer to the Variable Store Header.
343
344 Returns:
345
346 EfiRaw Variable store status is raw
347 EfiValid Variable store status is valid
348 EfiInvalid Variable store status is invalid
349
350 --*/
351 {
352 if (VarStoreHeader->Signature == VARIABLE_STORE_SIGNATURE &&
353 VarStoreHeader->Format == VARIABLE_STORE_FORMATTED &&
354 VarStoreHeader->State == VARIABLE_STORE_HEALTHY
355 ) {
356
357 return EfiValid;
358 } else if (VarStoreHeader->Signature == 0xffffffff &&
359 VarStoreHeader->Size == 0xffffffff &&
360 VarStoreHeader->Format == 0xff &&
361 VarStoreHeader->State == 0xff
362 ) {
363
364 return EfiRaw;
365 } else {
366 return EfiInvalid;
367 }
368 }
369
370
371 UINTN
372 NameSizeOfVariable (
373 IN VARIABLE_HEADER *Variable
374 )
375 /*++
376
377 Routine Description:
378
379 This code gets the size of name of variable.
380
381 Arguments:
382
383 Variable Pointer to the Variable Header.
384
385 Returns:
386
387 UINTN Size of variable in bytes
388
389 --*/
390 {
391 if (Variable->State == (UINT8) (-1) ||
392 Variable->DataSize == (UINT32) -1 ||
393 Variable->NameSize == (UINT32) -1 ||
394 Variable->Attributes == (UINT32) -1) {
395 return 0;
396 }
397 return (UINTN) Variable->NameSize;
398 }
399
400 UINTN
401 DataSizeOfVariable (
402 IN VARIABLE_HEADER *Variable
403 )
404 /*++
405
406 Routine Description:
407
408 This code gets the size of name of variable.
409
410 Arguments:
411
412 Variable Pointer to the Variable Header.
413
414 Returns:
415
416 UINTN Size of variable in bytes
417
418 --*/
419 {
420 if (Variable->State == (UINT8) -1 ||
421 Variable->DataSize == (UINT32) -1 ||
422 Variable->NameSize == (UINT32) -1 ||
423 Variable->Attributes == (UINT32) -1) {
424 return 0;
425 }
426 return (UINTN) Variable->DataSize;
427 }
428
429 CHAR16 *
430 GetVariableNamePtr (
431 IN VARIABLE_HEADER *Variable
432 )
433 /*++
434
435 Routine Description:
436
437 This code gets the pointer to the variable name.
438
439 Arguments:
440
441 Variable Pointer to the Variable Header.
442
443 Returns:
444
445 CHAR16* Pointer to Variable Name
446
447 --*/
448 {
449
450 return (CHAR16 *) (Variable + 1);
451 }
452
453 UINT8 *
454 GetVariableDataPtr (
455 IN VARIABLE_HEADER *Variable
456 )
457 /*++
458
459 Routine Description:
460
461 This code gets the pointer to the variable data.
462
463 Arguments:
464
465 Variable Pointer to the Variable Header.
466
467 Returns:
468
469 UINT8* Pointer to Variable Data
470
471 --*/
472 {
473 UINTN Value;
474
475 //
476 // Be careful about pad size for alignment
477 //
478 Value = (UINTN) GetVariableNamePtr (Variable);
479 Value += NameSizeOfVariable (Variable);
480 Value += GET_PAD_SIZE (NameSizeOfVariable (Variable));
481
482 return (UINT8 *) Value;
483 }
484
485
486 VARIABLE_HEADER *
487 GetNextVariablePtr (
488 IN VARIABLE_HEADER *Variable
489 )
490 /*++
491
492 Routine Description:
493
494 This code gets the pointer to the next variable header.
495
496 Arguments:
497
498 Variable Pointer to the Variable Header.
499
500 Returns:
501
502 VARIABLE_HEADER* Pointer to next variable header.
503
504 --*/
505 {
506 UINTN Value;
507
508 if (!IsValidVariableHeader (Variable)) {
509 return NULL;
510 }
511
512 Value = (UINTN) GetVariableDataPtr (Variable);
513 Value += DataSizeOfVariable (Variable);
514 Value += GET_PAD_SIZE (DataSizeOfVariable (Variable));
515
516 //
517 // Be careful about pad size for alignment
518 //
519 return (VARIABLE_HEADER *) HEADER_ALIGN (Value);
520 }
521
522 VARIABLE_HEADER *
523 GetStartPointer (
524 IN VARIABLE_STORE_HEADER *VarStoreHeader
525 )
526 /*++
527
528 Routine Description:
529
530 This code gets the pointer to the first variable memory pointer byte
531
532 Arguments:
533
534 VarStoreHeader Pointer to the Variable Store Header.
535
536 Returns:
537
538 VARIABLE_HEADER* Pointer to last unavailable Variable Header
539
540 --*/
541 {
542 //
543 // The end of variable store
544 //
545 return (VARIABLE_HEADER *) HEADER_ALIGN (VarStoreHeader + 1);
546 }
547
548 VARIABLE_HEADER *
549 GetEndPointer (
550 IN VARIABLE_STORE_HEADER *VarStoreHeader
551 )
552 /*++
553
554 Routine Description:
555
556 This code gets the pointer to the last variable memory pointer byte
557
558 Arguments:
559
560 VarStoreHeader Pointer to the Variable Store Header.
561
562 Returns:
563
564 VARIABLE_HEADER* Pointer to last unavailable Variable Header
565
566 --*/
567 {
568 //
569 // The end of variable store
570 //
571 return (VARIABLE_HEADER *) HEADER_ALIGN ((UINTN) VarStoreHeader + VarStoreHeader->Size);
572 }
573
574
575 EFI_STATUS
576 Reclaim (
577 IN EFI_PHYSICAL_ADDRESS VariableBase,
578 OUT UINTN *LastVariableOffset,
579 IN BOOLEAN IsVolatile,
580 IN VARIABLE_HEADER *UpdatingVariable
581 )
582 /*++
583
584 Routine Description:
585
586 Variable store garbage collection and reclaim operation
587
588 Arguments:
589
590 VariableBase Base address of variable store
591 LastVariableOffset Offset of last variable
592 IsVolatile The variable store is volatile or not,
593 if it is non-volatile, need FTW
594
595 Returns:
596
597 EFI STATUS
598
599 --*/
600 {
601 VARIABLE_HEADER *Variable;
602 VARIABLE_HEADER *AddedVariable;
603 VARIABLE_HEADER *NextVariable;
604 VARIABLE_HEADER *NextAddedVariable;
605 VARIABLE_STORE_HEADER *VariableStoreHeader;
606 UINT8 *ValidBuffer;
607 UINTN MaximumBufferSize;
608 UINTN VariableSize;
609 UINTN VariableNameSize;
610 UINTN UpdatingVariableNameSize;
611 UINTN NameSize;
612 UINT8 *CurrPtr;
613 VOID *Point0;
614 VOID *Point1;
615 BOOLEAN FoundAdded;
616 EFI_STATUS Status;
617 CHAR16 *VariableNamePtr;
618 CHAR16 *UpdatingVariableNamePtr;
619
620 VariableStoreHeader = (VARIABLE_STORE_HEADER *) ((UINTN) VariableBase);
621
622 //
623 // Start Pointers for the variable.
624 //
625 Variable = GetStartPointer (VariableStoreHeader);
626 MaximumBufferSize = sizeof (VARIABLE_STORE_HEADER);
627
628 while (IsValidVariableHeader (Variable)) {
629 NextVariable = GetNextVariablePtr (Variable);
630 if (Variable->State == VAR_ADDED ||
631 Variable->State == (VAR_IN_DELETED_TRANSITION & VAR_ADDED)
632 ) {
633 VariableSize = (UINTN) NextVariable - (UINTN) Variable;
634 MaximumBufferSize += VariableSize;
635 }
636
637 Variable = NextVariable;
638 }
639
640 //
641 // Reserve the 1 Bytes with Oxff to identify the
642 // end of the variable buffer.
643 //
644 MaximumBufferSize += 1;
645 ValidBuffer = AllocatePool (MaximumBufferSize);
646 if (ValidBuffer == NULL) {
647 return EFI_OUT_OF_RESOURCES;
648 }
649
650 SetMem (ValidBuffer, MaximumBufferSize, 0xff);
651
652 //
653 // Copy variable store header
654 //
655 CopyMem (ValidBuffer, VariableStoreHeader, sizeof (VARIABLE_STORE_HEADER));
656 CurrPtr = (UINT8 *) GetStartPointer ((VARIABLE_STORE_HEADER *) ValidBuffer);
657
658 //
659 // Start Pointers for the variable.
660 //
661
662 //
663 // Reinstall all ADDED variables as long as they are not identical to Updating Variable
664 //
665 Variable = GetStartPointer (VariableStoreHeader);
666 while (IsValidVariableHeader (Variable)) {
667 NextVariable = GetNextVariablePtr (Variable);
668 if (Variable->State == VAR_ADDED) {
669 if (UpdatingVariable != NULL) {
670 if (UpdatingVariable == Variable) {
671 Variable = NextVariable;
672 continue;
673 }
674
675 VariableNameSize = NameSizeOfVariable(Variable);
676 UpdatingVariableNameSize = NameSizeOfVariable(UpdatingVariable);
677
678 VariableNamePtr = GetVariableNamePtr (Variable);
679 UpdatingVariableNamePtr = GetVariableNamePtr (UpdatingVariable);
680 if (CompareGuid (&Variable->VendorGuid, &UpdatingVariable->VendorGuid) &&
681 VariableNameSize == UpdatingVariableNameSize &&
682 CompareMem (VariableNamePtr, UpdatingVariableNamePtr, VariableNameSize) == 0 ) {
683 Variable = NextVariable;
684 continue;
685 }
686 }
687 VariableSize = (UINTN) NextVariable - (UINTN) Variable;
688 CopyMem (CurrPtr, (UINT8 *) Variable, VariableSize);
689 CurrPtr += VariableSize;
690 }
691 Variable = NextVariable;
692 }
693
694 //
695 // Reinstall the variable being updated if it is not NULL
696 //
697 if (UpdatingVariable != NULL) {
698 VariableSize = (UINTN)(GetNextVariablePtr (UpdatingVariable)) - (UINTN)UpdatingVariable;
699 CopyMem (CurrPtr, (UINT8 *) UpdatingVariable, VariableSize);
700 CurrPtr += VariableSize;
701 }
702
703 //
704 // Reinstall all in delete transition variables
705 //
706 Variable = GetStartPointer (VariableStoreHeader);
707 while (IsValidVariableHeader (Variable)) {
708 NextVariable = GetNextVariablePtr (Variable);
709 if (Variable != UpdatingVariable && Variable->State == (VAR_IN_DELETED_TRANSITION & VAR_ADDED)) {
710
711 //
712 // Buffer has cached all ADDED variable.
713 // Per IN_DELETED variable, we have to guarantee that
714 // no ADDED one in previous buffer.
715 //
716
717 FoundAdded = FALSE;
718 AddedVariable = GetStartPointer ((VARIABLE_STORE_HEADER *) ValidBuffer);
719 while (IsValidVariableHeader (AddedVariable)) {
720 NextAddedVariable = GetNextVariablePtr (AddedVariable);
721 NameSize = NameSizeOfVariable (AddedVariable);
722 if (CompareGuid (&AddedVariable->VendorGuid, &Variable->VendorGuid) &&
723 NameSize == NameSizeOfVariable (Variable)
724 ) {
725 Point0 = (VOID *) GetVariableNamePtr (AddedVariable);
726 Point1 = (VOID *) GetVariableNamePtr (Variable);
727 if (CompareMem (Point0, Point1, NameSizeOfVariable (AddedVariable)) == 0) {
728 FoundAdded = TRUE;
729 break;
730 }
731 }
732 AddedVariable = NextAddedVariable;
733 }
734 if (!FoundAdded) {
735 //
736 // Promote VAR_IN_DELETED_TRANSITION to VAR_ADDED
737 //
738 VariableSize = (UINTN) NextVariable - (UINTN) Variable;
739 CopyMem (CurrPtr, (UINT8 *) Variable, VariableSize);
740 ((VARIABLE_HEADER *) CurrPtr)->State = VAR_ADDED;
741 CurrPtr += VariableSize;
742 }
743 }
744
745 Variable = NextVariable;
746 }
747
748 if (IsVolatile) {
749 //
750 // If volatile variable store, just copy valid buffer
751 //
752 SetMem ((UINT8 *) (UINTN) VariableBase, VariableStoreHeader->Size, 0xff);
753 CopyMem ((UINT8 *) (UINTN) VariableBase, ValidBuffer, (UINTN) (CurrPtr - (UINT8 *) ValidBuffer));
754 Status = EFI_SUCCESS;
755 } else {
756 //
757 // If non-volatile variable store, perform FTW here.
758 //
759 Status = FtwVariableSpace (
760 VariableBase,
761 ValidBuffer,
762 (UINTN) (CurrPtr - (UINT8 *) ValidBuffer)
763 );
764 }
765 if (!EFI_ERROR (Status)) {
766 *LastVariableOffset = (UINTN) (CurrPtr - (UINT8 *) ValidBuffer);
767 } else {
768 *LastVariableOffset = 0;
769 }
770
771 FreePool (ValidBuffer);
772
773 return Status;
774 }
775
776
777 //
778 // The current Hii implementation accesses this variable a larg # of times on every boot.
779 // Other common variables are only accessed a single time. This is why this cache algorithm
780 // only targets a single variable. Probably to get an performance improvement out of
781 // a Cache you would need a cache that improves the search performance for a variable.
782 //
783 VARIABLE_CACHE_ENTRY mVariableCache[] = {
784 {
785 &gEfiGlobalVariableGuid,
786 L"Lang",
787 0x00000000,
788 0x00,
789 NULL
790 }
791 };
792
793
794 /**
795 Update the Cache with Variable information. These are the same
796 arguments as the EFI Variable services.
797
798 @param[in] VariableName Name of variable
799 @param[in] VendorGuid Guid of variable
800 @param[in] Attribute Attribue of the variable
801 @param[in] DataSize Size of data. 0 means delete
802 @param[in] Data Variable data
803
804 **/
805 VOID
806 UpdateVariableCache (
807 IN CHAR16 *VariableName,
808 IN EFI_GUID *VendorGuid,
809 IN UINT32 Attributes,
810 IN UINTN DataSize,
811 IN VOID *Data
812 )
813 {
814 VARIABLE_CACHE_ENTRY *Entry;
815 UINTN Index;
816
817 if (EfiAtRuntime ()) {
818 // Don't use the cache at runtime
819 return;
820 }
821
822 for (Index = 0, Entry = mVariableCache; Index < sizeof (mVariableCache)/sizeof (VARIABLE_CACHE_ENTRY); Index++, Entry++) {
823 if (CompareGuid (VendorGuid, Entry->Guid)) {
824 if (StrCmp (VariableName, Entry->Name) == 0) {
825 Entry->Attributes = Attributes;
826 if (DataSize == 0) {
827 // Delete Case
828 if (Entry->DataSize != 0) {
829 FreePool (Entry->Data);
830 }
831 Entry->DataSize = DataSize;
832 } else if (DataSize == Entry->DataSize) {
833 CopyMem (Entry->Data, Data, DataSize);
834 } else {
835 Entry->Data = AllocatePool (DataSize);
836 Entry->DataSize = DataSize;
837 CopyMem (Entry->Data, Data, DataSize);
838 }
839 }
840 }
841 }
842 }
843
844
845 /**
846 Search the cache to see if the variable is in the cache.
847
848 @param[in] VariableName Name of variable
849 @param[in] VendorGuid Guid of variable
850 @param[in] Attribute Attribue returned
851 @param[in] DataSize Size of data returned
852 @param[in] Data Variable data returned
853
854 @retval EFI_SUCCESS VariableGuid & VariableName data was returned.
855 @retval other Not found.
856
857 **/
858 EFI_STATUS
859 FindVariableInCache (
860 IN CHAR16 *VariableName,
861 IN EFI_GUID *VendorGuid,
862 OUT UINT32 *Attributes OPTIONAL,
863 IN OUT UINTN *DataSize,
864 OUT VOID *Data
865 )
866 {
867 VARIABLE_CACHE_ENTRY *Entry;
868 UINTN Index;
869
870 if (EfiAtRuntime ()) {
871 // Don't use the cache at runtime
872 return EFI_NOT_FOUND;
873 }
874
875 for (Index = 0, Entry = mVariableCache; Index < sizeof (mVariableCache)/sizeof (VARIABLE_CACHE_ENTRY); Index++, Entry++) {
876 if (CompareGuid (VendorGuid, Entry->Guid)) {
877 if (StrCmp (VariableName, Entry->Name) == 0) {
878 if (Entry->DataSize == 0) {
879 // Variable was deleted so return not found
880 return EFI_NOT_FOUND;
881 } else if (Entry->DataSize > *DataSize) {
882 // If the buffer is too small return correct size
883 *DataSize = Entry->DataSize;
884 return EFI_BUFFER_TOO_SMALL;
885 } else {
886 *DataSize = Entry->DataSize;
887 // Return the data
888 CopyMem (Data, Entry->Data, Entry->DataSize);
889 if (Attributes != NULL) {
890 *Attributes = Entry->Attributes;
891 }
892 return EFI_SUCCESS;
893 }
894 }
895 }
896 }
897
898 return EFI_NOT_FOUND;
899 }
900
901
902 EFI_STATUS
903 FindVariable (
904 IN CHAR16 *VariableName,
905 IN EFI_GUID *VendorGuid,
906 OUT VARIABLE_POINTER_TRACK *PtrTrack,
907 IN VARIABLE_GLOBAL *Global
908 )
909 /*++
910
911 Routine Description:
912
913 This code finds variable in storage blocks (Volatile or Non-Volatile)
914
915 Arguments:
916
917 VariableName Name of the variable to be found
918 VendorGuid Vendor GUID to be found.
919 PtrTrack Variable Track Pointer structure that contains
920 Variable Information.
921 Contains the pointer of Variable header.
922 Global VARIABLE_GLOBAL pointer
923
924 Returns:
925
926 EFI STATUS
927
928 --*/
929 {
930 VARIABLE_HEADER *Variable[2];
931 VARIABLE_HEADER *InDeletedVariable;
932 VARIABLE_STORE_HEADER *VariableStoreHeader[2];
933 UINTN InDeletedStorageIndex;
934 UINTN Index;
935 VOID *Point;
936
937 //
938 // 0: Volatile, 1: Non-Volatile
939 // The index and attributes mapping must be kept in this order as RuntimeServiceGetNextVariableName
940 // make use of this mapping to implement search algorithme.
941 //
942 VariableStoreHeader[0] = (VARIABLE_STORE_HEADER *) ((UINTN) mVariableModuleGlobal->VariableGlobal.VolatileVariableBase);
943 VariableStoreHeader[1] = (VARIABLE_STORE_HEADER *) ((UINTN) mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase);
944
945 //
946 // Start Pointers for the variable.
947 // Actual Data Pointer where data can be written.
948 //
949 Variable[0] = GetStartPointer (VariableStoreHeader[0]);
950 Variable[1] = GetStartPointer (VariableStoreHeader[1]);
951
952 if (VariableName[0] != 0 && VendorGuid == NULL) {
953 return EFI_INVALID_PARAMETER;
954 }
955
956 //
957 // Find the variable by walk through volatile and then non-volatile variable store
958 //
959 InDeletedVariable = NULL;
960 InDeletedStorageIndex = 0;
961 for (Index = 0; Index < 2; Index++) {
962 while (IsValidVariableHeader (Variable[Index]) && (Variable[Index] <= GetEndPointer (VariableStoreHeader[Index]))) {
963 if (Variable[Index]->State == VAR_ADDED ||
964 Variable[Index]->State == (VAR_IN_DELETED_TRANSITION & VAR_ADDED)
965 ) {
966 if (!EfiAtRuntime () || (Variable[Index]->Attributes & EFI_VARIABLE_RUNTIME_ACCESS)) {
967 if (VariableName[0] == 0) {
968 if (Variable[Index]->State == (VAR_IN_DELETED_TRANSITION & VAR_ADDED)) {
969 InDeletedVariable = Variable[Index];
970 InDeletedStorageIndex = Index;
971 } else {
972 PtrTrack->StartPtr = GetStartPointer (VariableStoreHeader[Index]);
973 PtrTrack->EndPtr = GetEndPointer (VariableStoreHeader[Index]);
974 PtrTrack->CurrPtr = Variable[Index];
975 PtrTrack->Volatile = (BOOLEAN)(Index == 0);
976
977 return EFI_SUCCESS;
978 }
979 } else {
980 if (CompareGuid (VendorGuid, &Variable[Index]->VendorGuid)) {
981 Point = (VOID *) GetVariableNamePtr (Variable[Index]);
982
983 ASSERT (NameSizeOfVariable (Variable[Index]) != 0);
984 if (!CompareMem (VariableName, Point, NameSizeOfVariable (Variable[Index]))) {
985 if (Variable[Index]->State == (VAR_IN_DELETED_TRANSITION & VAR_ADDED)) {
986 InDeletedVariable = Variable[Index];
987 InDeletedStorageIndex = Index;
988 } else {
989 PtrTrack->StartPtr = GetStartPointer (VariableStoreHeader[Index]);
990 PtrTrack->EndPtr = GetEndPointer (VariableStoreHeader[Index]);
991 PtrTrack->CurrPtr = Variable[Index];
992 PtrTrack->Volatile = (BOOLEAN)(Index == 0);
993
994 return EFI_SUCCESS;
995 }
996 }
997 }
998 }
999 }
1000 }
1001
1002 Variable[Index] = GetNextVariablePtr (Variable[Index]);
1003 }
1004 if (InDeletedVariable != NULL) {
1005 PtrTrack->StartPtr = GetStartPointer (VariableStoreHeader[InDeletedStorageIndex]);
1006 PtrTrack->EndPtr = GetEndPointer (VariableStoreHeader[InDeletedStorageIndex]);
1007 PtrTrack->CurrPtr = InDeletedVariable;
1008 PtrTrack->Volatile = (BOOLEAN)(InDeletedStorageIndex == 0);
1009 return EFI_SUCCESS;
1010 }
1011 }
1012 PtrTrack->CurrPtr = NULL;
1013 return EFI_NOT_FOUND;
1014 }
1015
1016
1017
1018 /*++
1019
1020 Routine Description:
1021
1022 This code finds variable in storage blocks (Volatile or Non-Volatile)
1023
1024 Arguments:
1025
1026 VariableName Name of Variable to be found
1027 VendorGuid Variable vendor GUID
1028 Attributes OPTIONAL Attribute value of the variable found
1029 DataSize Size of Data found. If size is less than the
1030 data, this value contains the required size.
1031 Data Data pointer
1032 Global Pointer to VARIABLE_GLOBAL structure
1033 Instance Instance of the Firmware Volume.
1034
1035 Returns:
1036
1037 EFI_INVALID_PARAMETER - Invalid parameter
1038 EFI_SUCCESS - Find the specified variable
1039 EFI_NOT_FOUND - Not found
1040 EFI_BUFFER_TO_SMALL - DataSize is too small for the result
1041
1042
1043 --*/
1044 EFI_STATUS
1045 EFIAPI
1046 RuntimeServiceGetVariable (
1047 IN CHAR16 *VariableName,
1048 IN EFI_GUID *VendorGuid,
1049 OUT UINT32 *Attributes OPTIONAL,
1050 IN OUT UINTN *DataSize,
1051 OUT VOID *Data
1052 )
1053 {
1054 EFI_STATUS Status;
1055 VARIABLE_POINTER_TRACK Variable;
1056 UINTN VarDataSize;
1057
1058 if (VariableName == NULL || VendorGuid == NULL || DataSize == NULL) {
1059 return EFI_INVALID_PARAMETER;
1060 }
1061
1062 AcquireLockOnlyAtBootTime(&mVariableModuleGlobal->VariableGlobal.VariableServicesLock);
1063
1064 //
1065 // Find existing variable
1066 //
1067 Status = FindVariableInCache (VariableName, VendorGuid, Attributes, DataSize, Data);
1068 if ((Status == EFI_BUFFER_TOO_SMALL) || (Status == EFI_SUCCESS)){
1069 // Hit in the Cache
1070 UpdateVariableInfo (VariableName, VendorGuid, FALSE, TRUE, FALSE, FALSE, TRUE);
1071 goto Done;
1072 }
1073
1074 Status = FindVariable (VariableName, VendorGuid, &Variable, &mVariableModuleGlobal->VariableGlobal);
1075 if (Variable.CurrPtr == NULL || EFI_ERROR (Status)) {
1076 goto Done;
1077 }
1078
1079 //
1080 // Get data size
1081 //
1082 VarDataSize = DataSizeOfVariable (Variable.CurrPtr);
1083 ASSERT (VarDataSize != 0);
1084
1085 if (*DataSize >= VarDataSize) {
1086 if (Data == NULL) {
1087 Status = EFI_INVALID_PARAMETER;
1088 goto Done;
1089 }
1090
1091 CopyMem (Data, GetVariableDataPtr (Variable.CurrPtr), VarDataSize);
1092 if (Attributes != NULL) {
1093 *Attributes = Variable.CurrPtr->Attributes;
1094 }
1095
1096 *DataSize = VarDataSize;
1097 UpdateVariableInfo (VariableName, VendorGuid, Variable.Volatile, TRUE, FALSE, FALSE, FALSE);
1098 UpdateVariableCache (VariableName, VendorGuid, Variable.CurrPtr->Attributes, VarDataSize, Data);
1099
1100 Status = EFI_SUCCESS;
1101 goto Done;
1102 } else {
1103 *DataSize = VarDataSize;
1104 Status = EFI_BUFFER_TOO_SMALL;
1105 goto Done;
1106 }
1107
1108 Done:
1109 ReleaseLockOnlyAtBootTime (&mVariableModuleGlobal->VariableGlobal.VariableServicesLock);
1110 return Status;
1111 }
1112
1113
1114
1115 /*++
1116
1117 Routine Description:
1118
1119 This code Finds the Next available variable
1120
1121 Arguments:
1122
1123 VariableNameSize Size of the variable
1124 VariableName Pointer to variable name
1125 VendorGuid Variable Vendor Guid
1126 Global VARIABLE_GLOBAL structure pointer.
1127 Instance FV instance
1128
1129 Returns:
1130
1131 EFI STATUS
1132
1133 --*/
1134 EFI_STATUS
1135 EFIAPI
1136 RuntimeServiceGetNextVariableName (
1137 IN OUT UINTN *VariableNameSize,
1138 IN OUT CHAR16 *VariableName,
1139 IN OUT EFI_GUID *VendorGuid
1140 )
1141 {
1142 VARIABLE_POINTER_TRACK Variable;
1143 UINTN VarNameSize;
1144 EFI_STATUS Status;
1145
1146 if (VariableNameSize == NULL || VariableName == NULL || VendorGuid == NULL) {
1147 return EFI_INVALID_PARAMETER;
1148 }
1149
1150 AcquireLockOnlyAtBootTime(&mVariableModuleGlobal->VariableGlobal.VariableServicesLock);
1151
1152 Status = FindVariable (VariableName, VendorGuid, &Variable, &mVariableModuleGlobal->VariableGlobal);
1153 if (Variable.CurrPtr == NULL || EFI_ERROR (Status)) {
1154 goto Done;
1155 }
1156
1157 if (VariableName[0] != 0) {
1158 //
1159 // If variable name is not NULL, get next variable
1160 //
1161 Variable.CurrPtr = GetNextVariablePtr (Variable.CurrPtr);
1162 }
1163
1164 while (TRUE) {
1165 //
1166 // If both volatile and non-volatile variable store are parsed,
1167 // return not found
1168 //
1169 if (Variable.CurrPtr >= Variable.EndPtr || Variable.CurrPtr == NULL) {
1170 Variable.Volatile = (BOOLEAN) (Variable.Volatile ^ ((BOOLEAN) 0x1));
1171 if (!Variable.Volatile) {
1172 Variable.StartPtr = GetStartPointer ((VARIABLE_STORE_HEADER *) (UINTN) mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase);
1173 Variable.EndPtr = GetEndPointer ((VARIABLE_STORE_HEADER *) ((UINTN) mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase));
1174 } else {
1175 Status = EFI_NOT_FOUND;
1176 goto Done;
1177 }
1178
1179 Variable.CurrPtr = Variable.StartPtr;
1180 if (!IsValidVariableHeader (Variable.CurrPtr)) {
1181 continue;
1182 }
1183 }
1184 //
1185 // Variable is found
1186 //
1187 if (IsValidVariableHeader (Variable.CurrPtr) && Variable.CurrPtr->State == VAR_ADDED) {
1188 if (!(EfiAtRuntime () && !(Variable.CurrPtr->Attributes & EFI_VARIABLE_RUNTIME_ACCESS))) {
1189 VarNameSize = NameSizeOfVariable (Variable.CurrPtr);
1190 ASSERT (VarNameSize != 0);
1191
1192 if (VarNameSize <= *VariableNameSize) {
1193 CopyMem (
1194 VariableName,
1195 GetVariableNamePtr (Variable.CurrPtr),
1196 VarNameSize
1197 );
1198 CopyMem (
1199 VendorGuid,
1200 &Variable.CurrPtr->VendorGuid,
1201 sizeof (EFI_GUID)
1202 );
1203 Status = EFI_SUCCESS;
1204 } else {
1205 Status = EFI_BUFFER_TOO_SMALL;
1206 }
1207
1208 *VariableNameSize = VarNameSize;
1209 goto Done;
1210 }
1211 }
1212
1213 Variable.CurrPtr = GetNextVariablePtr (Variable.CurrPtr);
1214 }
1215
1216 Done:
1217 ReleaseLockOnlyAtBootTime (&mVariableModuleGlobal->VariableGlobal.VariableServicesLock);
1218 return Status;
1219 }
1220
1221
1222 /*++
1223
1224 Routine Description:
1225
1226 This code sets variable in storage blocks (Volatile or Non-Volatile)
1227
1228 Arguments:
1229
1230 VariableName Name of Variable to be found
1231 VendorGuid Variable vendor GUID
1232 Attributes Attribute value of the variable found
1233 DataSize Size of Data found. If size is less than the
1234 data, this value contains the required size.
1235 Data Data pointer
1236 Global Pointer to VARIABLE_GLOBAL structure
1237 VolatileOffset The offset of last volatile variable
1238 NonVolatileOffset The offset of last non-volatile variable
1239 Instance Instance of the Firmware Volume.
1240
1241 Returns:
1242
1243 EFI_INVALID_PARAMETER - Invalid parameter
1244 EFI_SUCCESS - Set successfully
1245 EFI_OUT_OF_RESOURCES - Resource not enough to set variable
1246 EFI_NOT_FOUND - Not found
1247 EFI_DEVICE_ERROR - Variable can not be saved due to hardware failure
1248 EFI_WRITE_PROTECTED - Variable is read-only
1249
1250 --*/
1251 EFI_STATUS
1252 EFIAPI
1253 RuntimeServiceSetVariable (
1254 IN CHAR16 *VariableName,
1255 IN EFI_GUID *VendorGuid,
1256 IN UINT32 Attributes,
1257 IN UINTN DataSize,
1258 IN VOID *Data
1259 )
1260 {
1261 VARIABLE_POINTER_TRACK Variable;
1262 EFI_STATUS Status;
1263 VARIABLE_HEADER *NextVariable;
1264 UINTN VarNameSize;
1265 UINTN VarNameOffset;
1266 UINTN VarDataOffset;
1267 UINTN VarSize;
1268 UINT8 State;
1269 BOOLEAN Reclaimed;
1270 UINTN *VolatileOffset;
1271 UINTN *NonVolatileOffset;
1272 UINT32 Instance;
1273 BOOLEAN Volatile;
1274 EFI_PHYSICAL_ADDRESS Point;
1275
1276 //
1277 // Check input parameters
1278 //
1279 if (VariableName == NULL || VariableName[0] == 0 || VendorGuid == NULL) {
1280 return EFI_INVALID_PARAMETER;
1281 }
1282 //
1283 // Make sure if runtime bit is set, boot service bit is set also
1284 //
1285 if ((Attributes & (EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS)) == EFI_VARIABLE_RUNTIME_ACCESS) {
1286 return EFI_INVALID_PARAMETER;
1287 }
1288
1289 //
1290 // The size of the VariableName, including the Unicode Null in bytes plus
1291 // the DataSize is limited to maximum size of MAX_HARDWARE_ERROR_VARIABLE_SIZE (32K)
1292 // bytes for HwErrRec, and MAX_VARIABLE_SIZE (1024) bytes for the others.
1293 //
1294 if ((Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == EFI_VARIABLE_HARDWARE_ERROR_RECORD) {
1295 if ((DataSize > MAX_HARDWARE_ERROR_VARIABLE_SIZE) ||
1296 (sizeof (VARIABLE_HEADER) + StrSize (VariableName) + DataSize > MAX_HARDWARE_ERROR_VARIABLE_SIZE)) {
1297 return EFI_INVALID_PARAMETER;
1298 }
1299 } else {
1300 //
1301 // The size of the VariableName, including the Unicode Null in bytes plus
1302 // the DataSize is limited to maximum size of MAX_VARIABLE_SIZE (1024) bytes.
1303 //
1304 if ((DataSize > MAX_VARIABLE_SIZE) ||
1305 (sizeof (VARIABLE_HEADER) + StrSize (VariableName) + DataSize > MAX_VARIABLE_SIZE)) {
1306 return EFI_INVALID_PARAMETER;
1307 }
1308 }
1309
1310 AcquireLockOnlyAtBootTime(&mVariableModuleGlobal->VariableGlobal.VariableServicesLock);
1311
1312 Reclaimed = FALSE;
1313 Instance = mVariableModuleGlobal->FvbInstance;
1314 VolatileOffset = &mVariableModuleGlobal->VolatileLastVariableOffset;
1315
1316 //
1317 // Consider reentrant in MCA/INIT/NMI. It needs be reupdated;
1318 //
1319 if (1 < InterlockedIncrement (&mVariableModuleGlobal->VariableGlobal.ReentrantState)) {
1320 Point = mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase;;
1321 //
1322 // Parse non-volatile variable data and get last variable offset
1323 //
1324 NextVariable = GetStartPointer ((VARIABLE_STORE_HEADER *) (UINTN) Point);
1325 while (IsValidVariableHeader (NextVariable)) {
1326 NextVariable = GetNextVariablePtr (NextVariable);
1327 }
1328 mVariableModuleGlobal->NonVolatileLastVariableOffset = (UINTN) NextVariable - (UINTN) Point;
1329 }
1330
1331 NonVolatileOffset = &mVariableModuleGlobal->NonVolatileLastVariableOffset;
1332
1333
1334 //
1335 // Check whether the input variable is already existed
1336 //
1337
1338 Status = FindVariable (VariableName, VendorGuid, &Variable, &mVariableModuleGlobal->VariableGlobal);
1339 if (Status == EFI_SUCCESS && Variable.CurrPtr != NULL) {
1340 //
1341 // Update/Delete existing variable
1342 //
1343 Volatile = Variable.Volatile;
1344
1345 if (EfiAtRuntime ()) {
1346 //
1347 // If EfiAtRuntime and the variable is Volatile and Runtime Access,
1348 // the volatile is ReadOnly, and SetVariable should be aborted and
1349 // return EFI_WRITE_PROTECTED.
1350 //
1351 if (Variable.Volatile) {
1352 Status = EFI_WRITE_PROTECTED;
1353 goto Done;
1354 }
1355 //
1356 // Only variable have NV attribute can be updated/deleted in Runtime
1357 //
1358 if (!(Variable.CurrPtr->Attributes & EFI_VARIABLE_NON_VOLATILE)) {
1359 Status = EFI_INVALID_PARAMETER;
1360 goto Done;
1361 }
1362 }
1363 //
1364 // Setting a data variable with no access, or zero DataSize attributes
1365 // specified causes it to be deleted.
1366 //
1367 if (DataSize == 0 || (Attributes & (EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS)) == 0) {
1368 State = Variable.CurrPtr->State;
1369 State &= VAR_DELETED;
1370
1371 Status = UpdateVariableStore (
1372 &mVariableModuleGlobal->VariableGlobal,
1373 Variable.Volatile,
1374 FALSE,
1375 Instance,
1376 (UINTN) &Variable.CurrPtr->State,
1377 sizeof (UINT8),
1378 &State
1379 );
1380 if (!EFI_ERROR (Status)) {
1381 UpdateVariableInfo (VariableName, VendorGuid, Volatile, FALSE, FALSE, TRUE, FALSE);
1382 UpdateVariableCache (VariableName, VendorGuid, Attributes, DataSize, Data);
1383 }
1384 goto Done;
1385 }
1386 //
1387 // If the variable is marked valid and the same data has been passed in
1388 // then return to the caller immediately.
1389 //
1390 if (DataSizeOfVariable (Variable.CurrPtr) == DataSize &&
1391 (CompareMem (Data, GetVariableDataPtr (Variable.CurrPtr), DataSize) == 0)) {
1392
1393 UpdateVariableInfo (VariableName, VendorGuid, Volatile, FALSE, TRUE, FALSE, FALSE);
1394 Status = EFI_SUCCESS;
1395 goto Done;
1396 } else if ((Variable.CurrPtr->State == VAR_ADDED) ||
1397 (Variable.CurrPtr->State == (VAR_ADDED & VAR_IN_DELETED_TRANSITION))) {
1398
1399 //
1400 // Mark the old variable as in delete transition
1401 //
1402 State = Variable.CurrPtr->State;
1403 State &= VAR_IN_DELETED_TRANSITION;
1404
1405 Status = UpdateVariableStore (
1406 &mVariableModuleGlobal->VariableGlobal,
1407 Variable.Volatile,
1408 FALSE,
1409 Instance,
1410 (UINTN) &Variable.CurrPtr->State,
1411 sizeof (UINT8),
1412 &State
1413 );
1414 if (EFI_ERROR (Status)) {
1415 goto Done;
1416 }
1417 }
1418 } else if (Status == EFI_NOT_FOUND) {
1419 //
1420 // Create a new variable
1421 //
1422
1423 //
1424 // Make sure we are trying to create a new variable.
1425 // Setting a data variable with no access, or zero DataSize attributes means to delete it.
1426 //
1427 if (DataSize == 0 || (Attributes & (EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS)) == 0) {
1428 Status = EFI_NOT_FOUND;
1429 goto Done;
1430 }
1431
1432 //
1433 // Only variable have NV|RT attribute can be created in Runtime
1434 //
1435 if (EfiAtRuntime () &&
1436 (!(Attributes & EFI_VARIABLE_RUNTIME_ACCESS) || !(Attributes & EFI_VARIABLE_NON_VOLATILE))) {
1437 Status = EFI_INVALID_PARAMETER;
1438 goto Done;
1439 }
1440 } else {
1441 //
1442 // Status should be EFI_INVALID_PARAMETER here according to return status of FindVariable().
1443 //
1444 ASSERT (Status == EFI_INVALID_PARAMETER);
1445 goto Done;
1446 }
1447
1448 //
1449 // Function part - create a new variable and copy the data.
1450 // Both update a variable and create a variable will come here.
1451 //
1452 // Tricky part: Use scratch data area at the end of volatile variable store
1453 // as a temporary storage.
1454 //
1455 NextVariable = GetEndPointer ((VARIABLE_STORE_HEADER *) ((UINTN) mVariableModuleGlobal->VariableGlobal.VolatileVariableBase));
1456
1457 SetMem (NextVariable, SCRATCH_SIZE, 0xff);
1458
1459 NextVariable->StartId = VARIABLE_DATA;
1460 NextVariable->Attributes = Attributes;
1461 //
1462 // NextVariable->State = VAR_ADDED;
1463 //
1464 NextVariable->Reserved = 0;
1465 VarNameOffset = sizeof (VARIABLE_HEADER);
1466 VarNameSize = StrSize (VariableName);
1467 CopyMem (
1468 (UINT8 *) ((UINTN) NextVariable + VarNameOffset),
1469 VariableName,
1470 VarNameSize
1471 );
1472 VarDataOffset = VarNameOffset + VarNameSize + GET_PAD_SIZE (VarNameSize);
1473 CopyMem (
1474 (UINT8 *) ((UINTN) NextVariable + VarDataOffset),
1475 Data,
1476 DataSize
1477 );
1478 CopyMem (&NextVariable->VendorGuid, VendorGuid, sizeof (EFI_GUID));
1479 //
1480 // There will be pad bytes after Data, the NextVariable->NameSize and
1481 // NextVariable->DataSize should not include pad size so that variable
1482 // service can get actual size in GetVariable
1483 //
1484 NextVariable->NameSize = (UINT32)VarNameSize;
1485 NextVariable->DataSize = (UINT32)DataSize;
1486
1487 //
1488 // The actual size of the variable that stores in storage should
1489 // include pad size.
1490 //
1491 VarSize = VarDataOffset + DataSize + GET_PAD_SIZE (DataSize);
1492 if (Attributes & EFI_VARIABLE_NON_VOLATILE) {
1493 //
1494 // Create a nonvolatile variable
1495 //
1496 Volatile = FALSE;
1497
1498 if ((UINT32) (VarSize +*NonVolatileOffset) >
1499 ((VARIABLE_STORE_HEADER *) ((UINTN) (mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase)))->Size
1500 ) {
1501 if (EfiAtRuntime ()) {
1502 Status = EFI_OUT_OF_RESOURCES;
1503 goto Done;
1504 }
1505 //
1506 // Perform garbage collection & reclaim operation
1507 //
1508 Status = Reclaim (mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase, NonVolatileOffset, FALSE, Variable.CurrPtr);
1509 if (EFI_ERROR (Status)) {
1510 goto Done;
1511 }
1512 //
1513 // If still no enough space, return out of resources
1514 //
1515 if ((UINT32) (VarSize +*NonVolatileOffset) >
1516 ((VARIABLE_STORE_HEADER *) ((UINTN) (mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase)))->Size
1517 ) {
1518 Status = EFI_OUT_OF_RESOURCES;
1519 goto Done;
1520 }
1521
1522 Reclaimed = TRUE;
1523 }
1524 //
1525 // Three steps
1526 // 1. Write variable header
1527 // 2. Set variable state to header valid
1528 // 3. Write variable data
1529 // 4. Set variable state to valid
1530 //
1531 //
1532 // Step 1:
1533 //
1534 Status = UpdateVariableStore (
1535 &mVariableModuleGlobal->VariableGlobal,
1536 FALSE,
1537 TRUE,
1538 Instance,
1539 *NonVolatileOffset,
1540 sizeof (VARIABLE_HEADER),
1541 (UINT8 *) NextVariable
1542 );
1543
1544 if (EFI_ERROR (Status)) {
1545 goto Done;
1546 }
1547
1548 //
1549 // Step 2:
1550 //
1551 NextVariable->State = VAR_HEADER_VALID_ONLY;
1552 Status = UpdateVariableStore (
1553 &mVariableModuleGlobal->VariableGlobal,
1554 FALSE,
1555 TRUE,
1556 Instance,
1557 *NonVolatileOffset,
1558 sizeof (VARIABLE_HEADER),
1559 (UINT8 *) NextVariable
1560 );
1561
1562 if (EFI_ERROR (Status)) {
1563 goto Done;
1564 }
1565 //
1566 // Step 3:
1567 //
1568 Status = UpdateVariableStore (
1569 &mVariableModuleGlobal->VariableGlobal,
1570 FALSE,
1571 TRUE,
1572 Instance,
1573 *NonVolatileOffset + sizeof (VARIABLE_HEADER),
1574 (UINT32) VarSize - sizeof (VARIABLE_HEADER),
1575 (UINT8 *) NextVariable + sizeof (VARIABLE_HEADER)
1576 );
1577
1578 if (EFI_ERROR (Status)) {
1579 goto Done;
1580 }
1581 //
1582 // Step 4:
1583 //
1584 NextVariable->State = VAR_ADDED;
1585 Status = UpdateVariableStore (
1586 &mVariableModuleGlobal->VariableGlobal,
1587 FALSE,
1588 TRUE,
1589 Instance,
1590 *NonVolatileOffset,
1591 sizeof (VARIABLE_HEADER),
1592 (UINT8 *) NextVariable
1593 );
1594
1595 if (EFI_ERROR (Status)) {
1596 goto Done;
1597 }
1598
1599 *NonVolatileOffset = HEADER_ALIGN (*NonVolatileOffset + VarSize);
1600
1601 } else {
1602 //
1603 // Create a volatile variable
1604 //
1605 Volatile = TRUE;
1606
1607 if ((UINT32) (VarSize +*VolatileOffset) >
1608 ((VARIABLE_STORE_HEADER *) ((UINTN) (mVariableModuleGlobal->VariableGlobal.VolatileVariableBase)))->Size) {
1609 //
1610 // Perform garbage collection & reclaim operation
1611 //
1612 Status = Reclaim (mVariableModuleGlobal->VariableGlobal.VolatileVariableBase, VolatileOffset, TRUE, Variable.CurrPtr);
1613 if (EFI_ERROR (Status)) {
1614 goto Done;
1615 }
1616 //
1617 // If still no enough space, return out of resources
1618 //
1619 if ((UINT32) (VarSize +*VolatileOffset) >
1620 ((VARIABLE_STORE_HEADER *) ((UINTN) (mVariableModuleGlobal->VariableGlobal.VolatileVariableBase)))->Size
1621 ) {
1622 Status = EFI_OUT_OF_RESOURCES;
1623 goto Done;
1624 }
1625
1626 Reclaimed = TRUE;
1627 }
1628
1629 NextVariable->State = VAR_ADDED;
1630 Status = UpdateVariableStore (
1631 &mVariableModuleGlobal->VariableGlobal,
1632 TRUE,
1633 TRUE,
1634 Instance,
1635 *VolatileOffset,
1636 (UINT32) VarSize,
1637 (UINT8 *) NextVariable
1638 );
1639
1640 if (EFI_ERROR (Status)) {
1641 goto Done;
1642 }
1643
1644 *VolatileOffset = HEADER_ALIGN (*VolatileOffset + VarSize);
1645 }
1646 //
1647 // Mark the old variable as deleted
1648 //
1649 if (!Reclaimed && !EFI_ERROR (Status) && Variable.CurrPtr != NULL) {
1650 State = Variable.CurrPtr->State;
1651 State &= VAR_DELETED;
1652
1653 Status = UpdateVariableStore (
1654 &mVariableModuleGlobal->VariableGlobal,
1655 Variable.Volatile,
1656 FALSE,
1657 Instance,
1658 (UINTN) &Variable.CurrPtr->State,
1659 sizeof (UINT8),
1660 &State
1661 );
1662
1663 if (!EFI_ERROR (Status)) {
1664 UpdateVariableInfo (VariableName, VendorGuid, Volatile, FALSE, TRUE, FALSE, FALSE);
1665 UpdateVariableCache (VariableName, VendorGuid, Attributes, DataSize, Data);
1666 }
1667 goto Done;
1668 }
1669
1670 Status = EFI_SUCCESS;
1671 UpdateVariableInfo (VariableName, VendorGuid, Volatile, FALSE, TRUE, FALSE, FALSE);
1672 UpdateVariableCache (VariableName, VendorGuid, Attributes, DataSize, Data);
1673
1674 Done:
1675 InterlockedDecrement (&mVariableModuleGlobal->VariableGlobal.ReentrantState);
1676 ReleaseLockOnlyAtBootTime (&mVariableModuleGlobal->VariableGlobal.VariableServicesLock);
1677
1678 return Status;
1679 }
1680
1681
1682 /*++
1683
1684 Routine Description:
1685
1686 This code returns information about the EFI variables.
1687
1688 Arguments:
1689
1690 Attributes Attributes bitmask to specify the type of variables
1691 on which to return information.
1692 MaximumVariableStorageSize Pointer to the maximum size of the storage space available
1693 for the EFI variables associated with the attributes specified.
1694 RemainingVariableStorageSize Pointer to the remaining size of the storage space available
1695 for EFI variables associated with the attributes specified.
1696 MaximumVariableSize Pointer to the maximum size of an individual EFI variables
1697 associated with the attributes specified.
1698 Global Pointer to VARIABLE_GLOBAL structure.
1699 Instance Instance of the Firmware Volume.
1700
1701 Returns:
1702
1703 EFI STATUS
1704 EFI_INVALID_PARAMETER - An invalid combination of attribute bits was supplied.
1705 EFI_SUCCESS - Query successfully.
1706 EFI_UNSUPPORTED - The attribute is not supported on this platform.
1707
1708 --*/
1709 EFI_STATUS
1710 EFIAPI
1711 RuntimeServiceQueryVariableInfo (
1712 IN UINT32 Attributes,
1713 OUT UINT64 *MaximumVariableStorageSize,
1714 OUT UINT64 *RemainingVariableStorageSize,
1715 OUT UINT64 *MaximumVariableSize
1716 )
1717 {
1718 VARIABLE_HEADER *Variable;
1719 VARIABLE_HEADER *NextVariable;
1720 UINT64 VariableSize;
1721 VARIABLE_STORE_HEADER *VariableStoreHeader;
1722
1723 if(MaximumVariableStorageSize == NULL || RemainingVariableStorageSize == NULL || MaximumVariableSize == NULL || Attributes == 0) {
1724 return EFI_INVALID_PARAMETER;
1725 }
1726
1727 if((Attributes & (EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_HARDWARE_ERROR_RECORD)) == 0) {
1728 //
1729 // Make sure the Attributes combination is supported by the platform.
1730 //
1731 return EFI_UNSUPPORTED;
1732 } else if ((Attributes & (EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS)) == EFI_VARIABLE_RUNTIME_ACCESS) {
1733 //
1734 // Make sure if runtime bit is set, boot service bit is set also.
1735 //
1736 return EFI_INVALID_PARAMETER;
1737 } else if (EfiAtRuntime () && !(Attributes & EFI_VARIABLE_RUNTIME_ACCESS)) {
1738 //
1739 // Make sure RT Attribute is set if we are in Runtime phase.
1740 //
1741 return EFI_INVALID_PARAMETER;
1742 }
1743
1744 AcquireLockOnlyAtBootTime(&mVariableModuleGlobal->VariableGlobal.VariableServicesLock);
1745
1746 if((Attributes & EFI_VARIABLE_NON_VOLATILE) == 0) {
1747 //
1748 // Query is Volatile related.
1749 //
1750 VariableStoreHeader = (VARIABLE_STORE_HEADER *) ((UINTN) mVariableModuleGlobal->VariableGlobal.VolatileVariableBase);
1751 } else {
1752 //
1753 // Query is Non-Volatile related.
1754 //
1755 VariableStoreHeader = (VARIABLE_STORE_HEADER *) ((UINTN) mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase);
1756 }
1757
1758 //
1759 // Now let's fill *MaximumVariableStorageSize *RemainingVariableStorageSize
1760 // with the storage size (excluding the storage header size).
1761 //
1762 *MaximumVariableStorageSize = VariableStoreHeader->Size - sizeof (VARIABLE_STORE_HEADER);
1763 *RemainingVariableStorageSize = VariableStoreHeader->Size - sizeof (VARIABLE_STORE_HEADER);
1764
1765 //
1766 // Let *MaximumVariableSize be MAX_VARIABLE_SIZE with the exception of the variable header size.
1767 //
1768 *MaximumVariableSize = MAX_VARIABLE_SIZE - sizeof (VARIABLE_HEADER);
1769
1770 //
1771 // Harware error record variable needs larger size.
1772 //
1773 if ((Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == EFI_VARIABLE_HARDWARE_ERROR_RECORD) {
1774 *MaximumVariableSize = MAX_HARDWARE_ERROR_VARIABLE_SIZE - sizeof (VARIABLE_HEADER);
1775 }
1776
1777 //
1778 // Point to the starting address of the variables.
1779 //
1780 Variable = GetStartPointer (VariableStoreHeader);
1781
1782 //
1783 // Now walk through the related variable store.
1784 //
1785 while (IsValidVariableHeader (Variable) && (Variable < GetEndPointer (VariableStoreHeader))) {
1786 NextVariable = GetNextVariablePtr (Variable);
1787 VariableSize = (UINT64) (UINTN) NextVariable - (UINT64) (UINTN) Variable;
1788
1789 if (EfiAtRuntime ()) {
1790 //
1791 // we don't take the state of the variables in mind
1792 // when calculating RemainingVariableStorageSize,
1793 // since the space occupied by variables not marked with
1794 // VAR_ADDED is not allowed to be reclaimed in Runtime.
1795 //
1796 *RemainingVariableStorageSize -= VariableSize;
1797 } else {
1798 //
1799 // Only care about Variables with State VAR_ADDED,because
1800 // the space not marked as VAR_ADDED is reclaimable now.
1801 //
1802 if (Variable->State == VAR_ADDED) {
1803 *RemainingVariableStorageSize -= VariableSize;
1804 }
1805 }
1806
1807 //
1808 // Go to the next one
1809 //
1810 Variable = NextVariable;
1811 }
1812
1813 if (*RemainingVariableStorageSize < sizeof (VARIABLE_HEADER)) {
1814 *MaximumVariableSize = 0;
1815 } else if ((*RemainingVariableStorageSize - sizeof (VARIABLE_HEADER)) < *MaximumVariableSize) {
1816 *MaximumVariableSize = *RemainingVariableStorageSize - sizeof (VARIABLE_HEADER);
1817 }
1818
1819 ReleaseLockOnlyAtBootTime (&mVariableModuleGlobal->VariableGlobal.VariableServicesLock);
1820 return EFI_SUCCESS;
1821 }
1822
1823 VOID
1824 EFIAPI
1825 ReclaimForOS(
1826 EFI_EVENT Event,
1827 VOID *Context
1828 )
1829 {
1830 UINT32 VarSize;
1831 EFI_STATUS Status;
1832
1833 VarSize = ((VARIABLE_STORE_HEADER *) ((UINTN) mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase))->Size;
1834 Status = EFI_SUCCESS;
1835
1836 //
1837 // Check if the free area is blow a threshold
1838 //
1839 if ((VarSize - mVariableModuleGlobal->NonVolatileLastVariableOffset) < VARIABLE_RECLAIM_THRESHOLD) {
1840 Status = Reclaim (
1841 mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase,
1842 &mVariableModuleGlobal->NonVolatileLastVariableOffset,
1843 FALSE,
1844 NULL
1845 );
1846 ASSERT_EFI_ERROR (Status);
1847 }
1848 }
1849
1850 EFI_STATUS
1851 VariableCommonInitialize (
1852 IN EFI_HANDLE ImageHandle,
1853 IN EFI_SYSTEM_TABLE *SystemTable
1854 )
1855 /*++
1856
1857 Routine Description:
1858 This function does common initialization for variable services
1859
1860 Arguments:
1861
1862 ImageHandle - The firmware allocated handle for the EFI image.
1863 SystemTable - A pointer to the EFI System Table.
1864
1865 Returns:
1866
1867 Status code.
1868
1869 EFI_NOT_FOUND - Variable store area not found.
1870 EFI_UNSUPPORTED - Currently only one non-volatile variable store is supported.
1871 EFI_SUCCESS - Variable services successfully initialized.
1872
1873 --*/
1874 {
1875 EFI_STATUS Status;
1876 EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader;
1877 CHAR8 *CurrPtr;
1878 VARIABLE_STORE_HEADER *VolatileVariableStore;
1879 VARIABLE_STORE_HEADER *VariableStoreHeader;
1880 VARIABLE_HEADER *NextVariable;
1881 UINT32 Instance;
1882 EFI_PHYSICAL_ADDRESS FvVolHdr;
1883 UINT64 TempVariableStoreHeader;
1884 EFI_GCD_MEMORY_SPACE_DESCRIPTOR GcdDescriptor;
1885 UINT64 BaseAddress;
1886 UINT64 Length;
1887 UINTN Index;
1888 UINT8 Data;
1889 UINT64 VariableStoreBase;
1890 UINT64 VariableStoreLength;
1891 EFI_EVENT ReadyToBootEvent;
1892
1893 Status = EFI_SUCCESS;
1894 //
1895 // Allocate runtime memory for variable driver global structure.
1896 //
1897 mVariableModuleGlobal = AllocateRuntimePool (sizeof (VARIABLE_MODULE_GLOBAL));
1898 if (mVariableModuleGlobal == NULL) {
1899 return EFI_OUT_OF_RESOURCES;
1900 }
1901
1902 EfiInitializeLock(&mVariableModuleGlobal->VariableGlobal.VariableServicesLock, TPL_NOTIFY);
1903 mVariableModuleGlobal->VariableGlobal.ReentrantState = 0;
1904
1905 //
1906 // Allocate memory for volatile variable store
1907 //
1908 VolatileVariableStore = AllocateRuntimePool (VARIABLE_STORE_SIZE + SCRATCH_SIZE);
1909 if (VolatileVariableStore == NULL) {
1910 FreePool (mVariableModuleGlobal);
1911 return EFI_OUT_OF_RESOURCES;
1912 }
1913
1914 SetMem (VolatileVariableStore, VARIABLE_STORE_SIZE + SCRATCH_SIZE, 0xff);
1915
1916 //
1917 // Variable Specific Data
1918 //
1919 mVariableModuleGlobal->VariableGlobal.VolatileVariableBase = (EFI_PHYSICAL_ADDRESS) (UINTN) VolatileVariableStore;
1920 mVariableModuleGlobal->VolatileLastVariableOffset = (UINTN) GetStartPointer (VolatileVariableStore) - (UINTN) VolatileVariableStore;
1921
1922 VolatileVariableStore->Signature = VARIABLE_STORE_SIGNATURE;
1923 VolatileVariableStore->Size = VARIABLE_STORE_SIZE;
1924 VolatileVariableStore->Format = VARIABLE_STORE_FORMATTED;
1925 VolatileVariableStore->State = VARIABLE_STORE_HEALTHY;
1926 VolatileVariableStore->Reserved = 0;
1927 VolatileVariableStore->Reserved1 = 0;
1928
1929 //
1930 // Get non volatile varaible store
1931 //
1932
1933 TempVariableStoreHeader = (UINT64) PcdGet32 (PcdFlashNvStorageVariableBase);
1934 VariableStoreBase = TempVariableStoreHeader + \
1935 (((EFI_FIRMWARE_VOLUME_HEADER *) (UINTN) (TempVariableStoreHeader)) -> HeaderLength);
1936 VariableStoreLength = (UINT64) PcdGet32 (PcdFlashNvStorageVariableSize) - \
1937 (((EFI_FIRMWARE_VOLUME_HEADER *) (UINTN) (TempVariableStoreHeader)) -> HeaderLength);
1938 //
1939 // Mark the variable storage region of the FLASH as RUNTIME
1940 //
1941 BaseAddress = VariableStoreBase & (~EFI_PAGE_MASK);
1942 Length = VariableStoreLength + (VariableStoreBase - BaseAddress);
1943 Length = (Length + EFI_PAGE_SIZE - 1) & (~EFI_PAGE_MASK);
1944
1945 Status = gDS->GetMemorySpaceDescriptor (BaseAddress, &GcdDescriptor);
1946 if (EFI_ERROR (Status)) {
1947 goto Done;
1948 }
1949
1950 Status = gDS->SetMemorySpaceAttributes (
1951 BaseAddress,
1952 Length,
1953 GcdDescriptor.Attributes | EFI_MEMORY_RUNTIME
1954 );
1955 if (EFI_ERROR (Status)) {
1956 goto Done;
1957 }
1958 //
1959 // Get address of non volatile variable store base
1960 //
1961 mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase = VariableStoreBase;
1962
1963 //
1964 // Check Integrity
1965 //
1966 //
1967 // Find the Correct Instance of the FV Block Service.
1968 //
1969 Instance = 0;
1970 CurrPtr = (CHAR8 *) ((UINTN) mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase);
1971 while (EfiFvbGetPhysicalAddress (Instance, &FvVolHdr) == EFI_SUCCESS) {
1972 FwVolHeader = (EFI_FIRMWARE_VOLUME_HEADER *) ((UINTN) FvVolHdr);
1973 if (CurrPtr >= (CHAR8 *) FwVolHeader && CurrPtr < (((CHAR8 *) FwVolHeader) + FwVolHeader->FvLength)) {
1974 mVariableModuleGlobal->FvbInstance = Instance;
1975 break;
1976 }
1977
1978 Instance++;
1979 }
1980
1981 VariableStoreHeader = (VARIABLE_STORE_HEADER *) CurrPtr;
1982 if (GetVariableStoreStatus (VariableStoreHeader) == EfiValid) {
1983 if (~VariableStoreHeader->Size == 0) {
1984 Status = UpdateVariableStore (
1985 &mVariableModuleGlobal->VariableGlobal,
1986 FALSE,
1987 FALSE,
1988 mVariableModuleGlobal->FvbInstance,
1989 (UINTN) &VariableStoreHeader->Size,
1990 sizeof (UINT32),
1991 (UINT8 *) &VariableStoreLength
1992 );
1993 //
1994 // As Variables are stored in NV storage, which are slow devices,such as flash.
1995 // Variable operation may skip checking variable program result to improve performance,
1996 // We can assume Variable program is OK through some check point.
1997 // Variable Store Size Setting should be the first Variable write operation,
1998 // We can assume all Read/Write is OK if we can set Variable store size successfully.
1999 // If write fail, we will assert here
2000 //
2001 ASSERT(VariableStoreHeader->Size == VariableStoreLength);
2002
2003 if (EFI_ERROR (Status)) {
2004 goto Done;
2005 }
2006 }
2007
2008 mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase = (EFI_PHYSICAL_ADDRESS) ((UINTN) CurrPtr);
2009 //
2010 // Parse non-volatile variable data and get last variable offset
2011 //
2012 NextVariable = GetStartPointer ((VARIABLE_STORE_HEADER *) CurrPtr);
2013 Status = EFI_SUCCESS;
2014
2015 while (IsValidVariableHeader (NextVariable)) {
2016 NextVariable = GetNextVariablePtr (NextVariable);
2017 }
2018
2019 mVariableModuleGlobal->NonVolatileLastVariableOffset = (UINTN) NextVariable - (UINTN) CurrPtr;
2020
2021 //
2022 // Check if the free area is really free.
2023 //
2024 for (Index = mVariableModuleGlobal->NonVolatileLastVariableOffset; Index < VariableStoreHeader->Size; Index++) {
2025 Data = ((UINT8 *) (UINTN) mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase)[Index];
2026 if (Data != 0xff) {
2027 //
2028 // There must be something wrong in variable store, do reclaim operation.
2029 //
2030 Status = Reclaim (
2031 mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase,
2032 &mVariableModuleGlobal->NonVolatileLastVariableOffset,
2033 FALSE,
2034 NULL
2035 );
2036
2037 if (EFI_ERROR (Status)) {
2038 goto Done;
2039 }
2040
2041 break;
2042 }
2043 }
2044
2045 //
2046 // Register the event handling function to reclaim variable for OS usage.
2047 //
2048 Status = EfiCreateEventReadyToBootEx (
2049 TPL_NOTIFY,
2050 ReclaimForOS,
2051 NULL,
2052 &ReadyToBootEvent
2053 );
2054 }
2055
2056 Done:
2057 if (EFI_ERROR (Status)) {
2058 FreePool (mVariableModuleGlobal);
2059 FreePool (VolatileVariableStore);
2060 }
2061
2062 return Status;
2063 }
2064
2065 VOID
2066 EFIAPI
2067 VariableClassAddressChangeEvent (
2068 IN EFI_EVENT Event,
2069 IN VOID *Context
2070 )
2071 {
2072 EfiConvertPointer (
2073 0x0,
2074 (VOID **) &mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase
2075 );
2076 EfiConvertPointer (
2077 0x0,
2078 (VOID **) &mVariableModuleGlobal->VariableGlobal.VolatileVariableBase
2079 );
2080 EfiConvertPointer (0x0, (VOID **) &mVariableModuleGlobal);
2081 }
2082
2083
2084 /**
2085 Variable Driver main entry point. The Variable driver places the 4 EFI
2086 runtime services in the EFI System Table and installs arch protocols
2087 for variable read and write services being availible.
2088
2089 @param[in] ImageHandle The firmware allocated handle for the EFI image.
2090 @param[in] SystemTable A pointer to the EFI System Table.
2091
2092 @retval EFI_SUCCESS The entry point is executed successfully.
2093 @retval other Some error occurs when executing this entry point.
2094
2095 **/
2096 EFI_STATUS
2097 EFIAPI
2098 VariableServiceInitialize (
2099 IN EFI_HANDLE ImageHandle,
2100 IN EFI_SYSTEM_TABLE *SystemTable
2101 )
2102 {
2103 EFI_STATUS Status;
2104
2105 Status = VariableCommonInitialize (ImageHandle, SystemTable);
2106 ASSERT_EFI_ERROR (Status);
2107
2108 SystemTable->RuntimeServices->GetVariable = RuntimeServiceGetVariable;
2109 SystemTable->RuntimeServices->GetNextVariableName = RuntimeServiceGetNextVariableName;
2110 SystemTable->RuntimeServices->SetVariable = RuntimeServiceSetVariable;
2111 SystemTable->RuntimeServices->QueryVariableInfo = RuntimeServiceQueryVariableInfo;
2112
2113 //
2114 // Now install the Variable Runtime Architectural Protocol on a new handle
2115 //
2116 Status = gBS->InstallMultipleProtocolInterfaces (
2117 &mHandle,
2118 &gEfiVariableArchProtocolGuid, NULL,
2119 &gEfiVariableWriteArchProtocolGuid, NULL,
2120 NULL
2121 );
2122 ASSERT_EFI_ERROR (Status);
2123
2124 Status = gBS->CreateEvent (
2125 EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE,
2126 TPL_NOTIFY,
2127 VariableClassAddressChangeEvent,
2128 NULL,
2129 &mVirtualAddressChangeEvent
2130 );
2131 ASSERT_EFI_ERROR (Status);
2132
2133 return EFI_SUCCESS;
2134 }
2135