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