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