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