]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Universal/Variable/RuntimeDxe/Variable.c
1. The original code has a bug on calculate the size of SCRATCH_SIZE. It should be...
[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 // recaluate the total size of Common/HwErr type variables in non-volatile area.
601 //
602 if (!IsVolatile) {
603 mVariableModuleGlobal->CommonVariableTotalSize = 0;
604 mVariableModuleGlobal->HwErrVariableTotalSize = 0;
605 }
606
607 //
608 // Start Pointers for the variable.
609 //
610 Variable = GetStartPointer (VariableStoreHeader);
611 MaximumBufferSize = sizeof (VARIABLE_STORE_HEADER);
612
613 while (IsValidVariableHeader (Variable)) {
614 NextVariable = GetNextVariablePtr (Variable);
615 if (Variable->State == VAR_ADDED ||
616 Variable->State == (VAR_IN_DELETED_TRANSITION & VAR_ADDED)
617 ) {
618 VariableSize = (UINTN) NextVariable - (UINTN) Variable;
619 MaximumBufferSize += VariableSize;
620 }
621
622 Variable = NextVariable;
623 }
624
625 //
626 // Reserve the 1 Bytes with Oxff to identify the
627 // end of the variable buffer.
628 //
629 MaximumBufferSize += 1;
630 ValidBuffer = AllocatePool (MaximumBufferSize);
631 if (ValidBuffer == NULL) {
632 return EFI_OUT_OF_RESOURCES;
633 }
634
635 SetMem (ValidBuffer, MaximumBufferSize, 0xff);
636
637 //
638 // Copy variable store header
639 //
640 CopyMem (ValidBuffer, VariableStoreHeader, sizeof (VARIABLE_STORE_HEADER));
641 CurrPtr = (UINT8 *) GetStartPointer ((VARIABLE_STORE_HEADER *) ValidBuffer);
642
643 //
644 // Reinstall all ADDED variables as long as they are not identical to Updating Variable
645 //
646 Variable = GetStartPointer (VariableStoreHeader);
647 while (IsValidVariableHeader (Variable)) {
648 NextVariable = GetNextVariablePtr (Variable);
649 if (Variable->State == VAR_ADDED) {
650 if (UpdatingVariable != NULL) {
651 if (UpdatingVariable == Variable) {
652 Variable = NextVariable;
653 continue;
654 }
655
656 VariableNameSize = NameSizeOfVariable(Variable);
657 UpdatingVariableNameSize = NameSizeOfVariable(UpdatingVariable);
658
659 VariableNamePtr = GetVariableNamePtr (Variable);
660 UpdatingVariableNamePtr = GetVariableNamePtr (UpdatingVariable);
661 if (CompareGuid (&Variable->VendorGuid, &UpdatingVariable->VendorGuid) &&
662 VariableNameSize == UpdatingVariableNameSize &&
663 CompareMem (VariableNamePtr, UpdatingVariableNamePtr, VariableNameSize) == 0 ) {
664 Variable = NextVariable;
665 continue;
666 }
667 }
668 VariableSize = (UINTN) NextVariable - (UINTN) Variable;
669 CopyMem (CurrPtr, (UINT8 *) Variable, VariableSize);
670 CurrPtr += VariableSize;
671 if ((!IsVolatile) && ((Variable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == EFI_VARIABLE_HARDWARE_ERROR_RECORD)) {
672 mVariableModuleGlobal->HwErrVariableTotalSize += VariableSize;
673 } else if ((!IsVolatile) && ((Variable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) != EFI_VARIABLE_HARDWARE_ERROR_RECORD)) {
674 mVariableModuleGlobal->CommonVariableTotalSize += VariableSize;
675 }
676 }
677 Variable = NextVariable;
678 }
679
680 //
681 // Reinstall the variable being updated if it is not NULL
682 //
683 if (UpdatingVariable != NULL) {
684 VariableSize = (UINTN)(GetNextVariablePtr (UpdatingVariable)) - (UINTN)UpdatingVariable;
685 CopyMem (CurrPtr, (UINT8 *) UpdatingVariable, VariableSize);
686 CurrPtr += VariableSize;
687 if ((!IsVolatile) && ((UpdatingVariable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == EFI_VARIABLE_HARDWARE_ERROR_RECORD)) {
688 mVariableModuleGlobal->HwErrVariableTotalSize += VariableSize;
689 } else if ((!IsVolatile) && ((UpdatingVariable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) != EFI_VARIABLE_HARDWARE_ERROR_RECORD)) {
690 mVariableModuleGlobal->CommonVariableTotalSize += VariableSize;
691 }
692 }
693
694 //
695 // Reinstall all in delete transition variables
696 //
697 Variable = GetStartPointer (VariableStoreHeader);
698 while (IsValidVariableHeader (Variable)) {
699 NextVariable = GetNextVariablePtr (Variable);
700 if (Variable != UpdatingVariable && Variable->State == (VAR_IN_DELETED_TRANSITION & VAR_ADDED)) {
701
702 //
703 // Buffer has cached all ADDED variable.
704 // Per IN_DELETED variable, we have to guarantee that
705 // no ADDED one in previous buffer.
706 //
707
708 FoundAdded = FALSE;
709 AddedVariable = GetStartPointer ((VARIABLE_STORE_HEADER *) ValidBuffer);
710 while (IsValidVariableHeader (AddedVariable)) {
711 NextAddedVariable = GetNextVariablePtr (AddedVariable);
712 NameSize = NameSizeOfVariable (AddedVariable);
713 if (CompareGuid (&AddedVariable->VendorGuid, &Variable->VendorGuid) &&
714 NameSize == NameSizeOfVariable (Variable)
715 ) {
716 Point0 = (VOID *) GetVariableNamePtr (AddedVariable);
717 Point1 = (VOID *) GetVariableNamePtr (Variable);
718 if (CompareMem (Point0, Point1, NameSizeOfVariable (AddedVariable)) == 0) {
719 FoundAdded = TRUE;
720 break;
721 }
722 }
723 AddedVariable = NextAddedVariable;
724 }
725 if (!FoundAdded) {
726 //
727 // Promote VAR_IN_DELETED_TRANSITION to VAR_ADDED
728 //
729 VariableSize = (UINTN) NextVariable - (UINTN) Variable;
730 CopyMem (CurrPtr, (UINT8 *) Variable, VariableSize);
731 ((VARIABLE_HEADER *) CurrPtr)->State = VAR_ADDED;
732 CurrPtr += VariableSize;
733 if ((!IsVolatile) && ((Variable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == EFI_VARIABLE_HARDWARE_ERROR_RECORD)) {
734 mVariableModuleGlobal->HwErrVariableTotalSize += VariableSize;
735 } else if ((!IsVolatile) && ((Variable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) != EFI_VARIABLE_HARDWARE_ERROR_RECORD)) {
736 mVariableModuleGlobal->CommonVariableTotalSize += VariableSize;
737 }
738 }
739 }
740
741 Variable = NextVariable;
742 }
743
744 if (IsVolatile) {
745 //
746 // If volatile variable store, just copy valid buffer
747 //
748 SetMem ((UINT8 *) (UINTN) VariableBase, VariableStoreHeader->Size, 0xff);
749 CopyMem ((UINT8 *) (UINTN) VariableBase, ValidBuffer, (UINTN) (CurrPtr - (UINT8 *) ValidBuffer));
750 Status = EFI_SUCCESS;
751 } else {
752 //
753 // If non-volatile variable store, perform FTW here.
754 //
755 Status = FtwVariableSpace (
756 VariableBase,
757 ValidBuffer,
758 (UINTN) (CurrPtr - (UINT8 *) ValidBuffer)
759 );
760 }
761 if (!EFI_ERROR (Status)) {
762 *LastVariableOffset = (UINTN) (CurrPtr - (UINT8 *) ValidBuffer);
763 } else {
764 *LastVariableOffset = 0;
765 }
766
767 FreePool (ValidBuffer);
768
769 return Status;
770 }
771
772
773 /**
774 Update the Cache with Variable information. These are the same
775 arguments as the EFI Variable services.
776
777 @param[in] VariableName Name of variable
778 @param[in] VendorGuid Guid of variable
779 @param[in] Attributes Attribues of the variable
780 @param[in] DataSize Size of data. 0 means delete
781 @param[in] Data Variable data
782
783 **/
784 VOID
785 UpdateVariableCache (
786 IN CHAR16 *VariableName,
787 IN EFI_GUID *VendorGuid,
788 IN UINT32 Attributes,
789 IN UINTN DataSize,
790 IN VOID *Data
791 )
792 {
793 VARIABLE_CACHE_ENTRY *Entry;
794 UINTN Index;
795
796 if (EfiAtRuntime ()) {
797 //
798 // Don't use the cache at runtime
799 //
800 return;
801 }
802
803 for (Index = 0, Entry = mVariableCache; Index < sizeof (mVariableCache)/sizeof (VARIABLE_CACHE_ENTRY); Index++, Entry++) {
804 if (CompareGuid (VendorGuid, Entry->Guid)) {
805 if (StrCmp (VariableName, Entry->Name) == 0) {
806 Entry->Attributes = Attributes;
807 if (DataSize == 0) {
808 //
809 // Delete Case
810 //
811 if (Entry->DataSize != 0) {
812 FreePool (Entry->Data);
813 }
814 Entry->DataSize = DataSize;
815 } else if (DataSize == Entry->DataSize) {
816 CopyMem (Entry->Data, Data, DataSize);
817 } else {
818 Entry->Data = AllocatePool (DataSize);
819 ASSERT (Entry->Data != NULL);
820
821 Entry->DataSize = DataSize;
822 CopyMem (Entry->Data, Data, DataSize);
823 }
824 }
825 }
826 }
827 }
828
829
830 /**
831 Search the cache to check if the variable is in it.
832
833 This function searches the variable cache. If the variable to find exists, return its data
834 and attributes.
835
836 @param VariableName A Null-terminated Unicode string that is the name of the vendor's
837 variable. Each VariableName is unique for each
838 VendorGuid.
839 @param VendorGuid A unique identifier for the vendor
840 @param Attributes Pointer to the attributes bitmask of the variable for output.
841 @param DataSize On input, size of the buffer of Data.
842 On output, size of the variable's data.
843 @param Data Pointer to the data buffer for output.
844
845 @retval EFI_SUCCESS VariableGuid & VariableName data was returned.
846 @retval EFI_NOT_FOUND No matching variable found in cache.
847 @retval EFI_BUFFER_TOO_SMALL *DataSize is smaller than size of the variable's data to return.
848
849 **/
850 EFI_STATUS
851 FindVariableInCache (
852 IN CHAR16 *VariableName,
853 IN EFI_GUID *VendorGuid,
854 OUT UINT32 *Attributes OPTIONAL,
855 IN OUT UINTN *DataSize,
856 OUT VOID *Data
857 )
858 {
859 VARIABLE_CACHE_ENTRY *Entry;
860 UINTN Index;
861
862 if (EfiAtRuntime ()) {
863 // Don't use the cache at runtime
864 return EFI_NOT_FOUND;
865 }
866
867 for (Index = 0, Entry = mVariableCache; Index < sizeof (mVariableCache)/sizeof (VARIABLE_CACHE_ENTRY); Index++, Entry++) {
868 if (CompareGuid (VendorGuid, Entry->Guid)) {
869 if (StrCmp (VariableName, Entry->Name) == 0) {
870 if (Entry->DataSize == 0) {
871 // Variable was deleted so return not found
872 return EFI_NOT_FOUND;
873 } else if (Entry->DataSize > *DataSize) {
874 // If the buffer is too small return correct size
875 *DataSize = Entry->DataSize;
876 return EFI_BUFFER_TOO_SMALL;
877 } else {
878 *DataSize = Entry->DataSize;
879 // Return the data
880 CopyMem (Data, Entry->Data, Entry->DataSize);
881 if (Attributes != NULL) {
882 *Attributes = Entry->Attributes;
883 }
884 return EFI_SUCCESS;
885 }
886 }
887 }
888 }
889
890 return EFI_NOT_FOUND;
891 }
892
893 /**
894 Finds variable in storage blocks of volatile and non-volatile storage areas.
895
896 This code finds variable in storage blocks of volatile and non-volatile storage areas.
897 If VariableName is an empty string, then we just return the first
898 qualified variable without comparing VariableName and VendorGuid.
899 Otherwise, VariableName and VendorGuid are compared.
900
901 @param VariableName Name of the variable to be found
902 @param VendorGuid Vendor GUID to be found.
903 @param PtrTrack VARIABLE_POINTER_TRACK structure for output,
904 including the range searched and the target position.
905 @param Global Pointer to VARIABLE_GLOBAL structure, including
906 base of volatile variable storage area, base of
907 NV variable storage area, and a lock.
908
909 @retval EFI_INVALID_PARAMETER If VariableName is not an empty string, while
910 VendorGuid is NULL
911 @retval EFI_SUCCESS Variable successfully found
912 @retval EFI_INVALID_PARAMETER Variable not found
913
914 **/
915 EFI_STATUS
916 FindVariable (
917 IN CHAR16 *VariableName,
918 IN EFI_GUID *VendorGuid,
919 OUT VARIABLE_POINTER_TRACK *PtrTrack,
920 IN VARIABLE_GLOBAL *Global
921 )
922 {
923 VARIABLE_HEADER *Variable[2];
924 VARIABLE_HEADER *InDeletedVariable;
925 VARIABLE_STORE_HEADER *VariableStoreHeader[2];
926 UINTN InDeletedStorageIndex;
927 UINTN Index;
928 VOID *Point;
929
930 //
931 // 0: Volatile, 1: Non-Volatile
932 // The index and attributes mapping must be kept in this order as RuntimeServiceGetNextVariableName
933 // make use of this mapping to implement search algorithme.
934 //
935 VariableStoreHeader[0] = (VARIABLE_STORE_HEADER *) ((UINTN) mVariableModuleGlobal->VariableGlobal.VolatileVariableBase);
936 VariableStoreHeader[1] = (VARIABLE_STORE_HEADER *) ((UINTN) mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase);
937
938 //
939 // Start Pointers for the variable.
940 // Actual Data Pointer where data can be written.
941 //
942 Variable[0] = GetStartPointer (VariableStoreHeader[0]);
943 Variable[1] = GetStartPointer (VariableStoreHeader[1]);
944
945 if (VariableName[0] != 0 && VendorGuid == NULL) {
946 return EFI_INVALID_PARAMETER;
947 }
948
949 //
950 // Find the variable by walk through volatile and then non-volatile variable store
951 //
952 InDeletedVariable = NULL;
953 InDeletedStorageIndex = 0;
954 for (Index = 0; Index < 2; Index++) {
955 while ((Variable[Index] < GetEndPointer (VariableStoreHeader[Index])) && IsValidVariableHeader (Variable[Index])) {
956 if (Variable[Index]->State == VAR_ADDED ||
957 Variable[Index]->State == (VAR_IN_DELETED_TRANSITION & VAR_ADDED)
958 ) {
959 if (!EfiAtRuntime () || ((Variable[Index]->Attributes & EFI_VARIABLE_RUNTIME_ACCESS) != 0)) {
960 if (VariableName[0] == 0) {
961 if (Variable[Index]->State == (VAR_IN_DELETED_TRANSITION & VAR_ADDED)) {
962 InDeletedVariable = Variable[Index];
963 InDeletedStorageIndex = Index;
964 } else {
965 PtrTrack->StartPtr = GetStartPointer (VariableStoreHeader[Index]);
966 PtrTrack->EndPtr = GetEndPointer (VariableStoreHeader[Index]);
967 PtrTrack->CurrPtr = Variable[Index];
968 PtrTrack->Volatile = (BOOLEAN)(Index == 0);
969
970 return EFI_SUCCESS;
971 }
972 } else {
973 if (CompareGuid (VendorGuid, &Variable[Index]->VendorGuid)) {
974 Point = (VOID *) GetVariableNamePtr (Variable[Index]);
975
976 ASSERT (NameSizeOfVariable (Variable[Index]) != 0);
977 if (CompareMem (VariableName, Point, NameSizeOfVariable (Variable[Index])) == 0) {
978 if (Variable[Index]->State == (VAR_IN_DELETED_TRANSITION & VAR_ADDED)) {
979 InDeletedVariable = Variable[Index];
980 InDeletedStorageIndex = Index;
981 } else {
982 PtrTrack->StartPtr = GetStartPointer (VariableStoreHeader[Index]);
983 PtrTrack->EndPtr = GetEndPointer (VariableStoreHeader[Index]);
984 PtrTrack->CurrPtr = Variable[Index];
985 PtrTrack->Volatile = (BOOLEAN)(Index == 0);
986
987 return EFI_SUCCESS;
988 }
989 }
990 }
991 }
992 }
993 }
994
995 Variable[Index] = GetNextVariablePtr (Variable[Index]);
996 }
997 if (InDeletedVariable != NULL) {
998 PtrTrack->StartPtr = GetStartPointer (VariableStoreHeader[InDeletedStorageIndex]);
999 PtrTrack->EndPtr = GetEndPointer (VariableStoreHeader[InDeletedStorageIndex]);
1000 PtrTrack->CurrPtr = InDeletedVariable;
1001 PtrTrack->Volatile = (BOOLEAN)(InDeletedStorageIndex == 0);
1002 return EFI_SUCCESS;
1003 }
1004 }
1005 PtrTrack->CurrPtr = NULL;
1006 return EFI_NOT_FOUND;
1007 }
1008
1009
1010 /**
1011
1012 This code finds variable in storage blocks (Volatile or Non-Volatile).
1013
1014 @param VariableName Name of Variable to be found.
1015 @param VendorGuid Variable vendor GUID.
1016 @param Attributes Attribute value of the variable found.
1017 @param DataSize Size of Data found. If size is less than the
1018 data, this value contains the required size.
1019 @param Data Data pointer.
1020
1021 @return EFI_INVALID_PARAMETER Invalid parameter
1022 @return EFI_SUCCESS Find the specified variable
1023 @return EFI_NOT_FOUND Not found
1024 @return EFI_BUFFER_TO_SMALL DataSize is too small for the result
1025
1026 **/
1027 EFI_STATUS
1028 EFIAPI
1029 RuntimeServiceGetVariable (
1030 IN CHAR16 *VariableName,
1031 IN EFI_GUID *VendorGuid,
1032 OUT UINT32 *Attributes OPTIONAL,
1033 IN OUT UINTN *DataSize,
1034 OUT VOID *Data
1035 )
1036 {
1037 EFI_STATUS Status;
1038 VARIABLE_POINTER_TRACK Variable;
1039 UINTN VarDataSize;
1040
1041 if (VariableName == NULL || VendorGuid == NULL || DataSize == NULL) {
1042 return EFI_INVALID_PARAMETER;
1043 }
1044
1045 AcquireLockOnlyAtBootTime(&mVariableModuleGlobal->VariableGlobal.VariableServicesLock);
1046
1047 //
1048 // Find existing variable
1049 //
1050 Status = FindVariableInCache (VariableName, VendorGuid, Attributes, DataSize, Data);
1051 if ((Status == EFI_BUFFER_TOO_SMALL) || (Status == EFI_SUCCESS)){
1052 // Hit in the Cache
1053 UpdateVariableInfo (VariableName, VendorGuid, FALSE, TRUE, FALSE, FALSE, TRUE);
1054 goto Done;
1055 }
1056
1057 Status = FindVariable (VariableName, VendorGuid, &Variable, &mVariableModuleGlobal->VariableGlobal);
1058 if (Variable.CurrPtr == NULL || EFI_ERROR (Status)) {
1059 goto Done;
1060 }
1061
1062 //
1063 // Get data size
1064 //
1065 VarDataSize = DataSizeOfVariable (Variable.CurrPtr);
1066 ASSERT (VarDataSize != 0);
1067
1068 if (*DataSize >= VarDataSize) {
1069 if (Data == NULL) {
1070 Status = EFI_INVALID_PARAMETER;
1071 goto Done;
1072 }
1073
1074 CopyMem (Data, GetVariableDataPtr (Variable.CurrPtr), VarDataSize);
1075 if (Attributes != NULL) {
1076 *Attributes = Variable.CurrPtr->Attributes;
1077 }
1078
1079 *DataSize = VarDataSize;
1080 UpdateVariableInfo (VariableName, VendorGuid, Variable.Volatile, TRUE, FALSE, FALSE, FALSE);
1081 UpdateVariableCache (VariableName, VendorGuid, Variable.CurrPtr->Attributes, VarDataSize, Data);
1082
1083 Status = EFI_SUCCESS;
1084 goto Done;
1085 } else {
1086 *DataSize = VarDataSize;
1087 Status = EFI_BUFFER_TOO_SMALL;
1088 goto Done;
1089 }
1090
1091 Done:
1092 ReleaseLockOnlyAtBootTime (&mVariableModuleGlobal->VariableGlobal.VariableServicesLock);
1093 return Status;
1094 }
1095
1096
1097
1098 /**
1099
1100 This code Finds the Next available variable.
1101
1102 @param VariableNameSize Size of the variable name
1103 @param VariableName Pointer to variable name
1104 @param VendorGuid Variable Vendor Guid
1105
1106 @return EFI_INVALID_PARAMETER Invalid parameter
1107 @return EFI_SUCCESS Find the specified variable
1108 @return EFI_NOT_FOUND Not found
1109 @return EFI_BUFFER_TO_SMALL DataSize is too small for the result
1110
1111 **/
1112 EFI_STATUS
1113 EFIAPI
1114 RuntimeServiceGetNextVariableName (
1115 IN OUT UINTN *VariableNameSize,
1116 IN OUT CHAR16 *VariableName,
1117 IN OUT EFI_GUID *VendorGuid
1118 )
1119 {
1120 VARIABLE_POINTER_TRACK Variable;
1121 UINTN VarNameSize;
1122 EFI_STATUS Status;
1123
1124 if (VariableNameSize == NULL || VariableName == NULL || VendorGuid == NULL) {
1125 return EFI_INVALID_PARAMETER;
1126 }
1127
1128 AcquireLockOnlyAtBootTime(&mVariableModuleGlobal->VariableGlobal.VariableServicesLock);
1129
1130 Status = FindVariable (VariableName, VendorGuid, &Variable, &mVariableModuleGlobal->VariableGlobal);
1131 if (Variable.CurrPtr == NULL || EFI_ERROR (Status)) {
1132 goto Done;
1133 }
1134
1135 if (VariableName[0] != 0) {
1136 //
1137 // If variable name is not NULL, get next variable
1138 //
1139 Variable.CurrPtr = GetNextVariablePtr (Variable.CurrPtr);
1140 }
1141
1142 while (TRUE) {
1143 //
1144 // If both volatile and non-volatile variable store are parsed,
1145 // return not found
1146 //
1147 if (Variable.CurrPtr >= Variable.EndPtr || Variable.CurrPtr == NULL) {
1148 Variable.Volatile = (BOOLEAN) (Variable.Volatile ^ ((BOOLEAN) 0x1));
1149 if (!Variable.Volatile) {
1150 Variable.StartPtr = GetStartPointer ((VARIABLE_STORE_HEADER *) (UINTN) mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase);
1151 Variable.EndPtr = GetEndPointer ((VARIABLE_STORE_HEADER *) ((UINTN) mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase));
1152 } else {
1153 Status = EFI_NOT_FOUND;
1154 goto Done;
1155 }
1156
1157 Variable.CurrPtr = Variable.StartPtr;
1158 if (!IsValidVariableHeader (Variable.CurrPtr)) {
1159 continue;
1160 }
1161 }
1162 //
1163 // Variable is found
1164 //
1165 if (IsValidVariableHeader (Variable.CurrPtr) && Variable.CurrPtr->State == VAR_ADDED) {
1166 if ((EfiAtRuntime () && ((Variable.CurrPtr->Attributes & EFI_VARIABLE_RUNTIME_ACCESS) == 0)) == 0) {
1167 VarNameSize = NameSizeOfVariable (Variable.CurrPtr);
1168 ASSERT (VarNameSize != 0);
1169
1170 if (VarNameSize <= *VariableNameSize) {
1171 CopyMem (
1172 VariableName,
1173 GetVariableNamePtr (Variable.CurrPtr),
1174 VarNameSize
1175 );
1176 CopyMem (
1177 VendorGuid,
1178 &Variable.CurrPtr->VendorGuid,
1179 sizeof (EFI_GUID)
1180 );
1181 Status = EFI_SUCCESS;
1182 } else {
1183 Status = EFI_BUFFER_TOO_SMALL;
1184 }
1185
1186 *VariableNameSize = VarNameSize;
1187 goto Done;
1188 }
1189 }
1190
1191 Variable.CurrPtr = GetNextVariablePtr (Variable.CurrPtr);
1192 }
1193
1194 Done:
1195 ReleaseLockOnlyAtBootTime (&mVariableModuleGlobal->VariableGlobal.VariableServicesLock);
1196 return Status;
1197 }
1198
1199 /**
1200
1201 This code sets variable in storage blocks (Volatile or Non-Volatile).
1202
1203 @param VariableName Name of Variable to be found
1204 @param VendorGuid Variable vendor GUID
1205 @param Attributes Attribute value of the variable found
1206 @param DataSize Size of Data found. If size is less than the
1207 data, this value contains the required size.
1208 @param Data Data pointer
1209
1210 @return EFI_INVALID_PARAMETER Invalid parameter
1211 @return EFI_SUCCESS Set successfully
1212 @return EFI_OUT_OF_RESOURCES Resource not enough to set variable
1213 @return EFI_NOT_FOUND Not found
1214 @return EFI_WRITE_PROTECTED Variable is read-only
1215
1216 **/
1217 EFI_STATUS
1218 EFIAPI
1219 RuntimeServiceSetVariable (
1220 IN CHAR16 *VariableName,
1221 IN EFI_GUID *VendorGuid,
1222 IN UINT32 Attributes,
1223 IN UINTN DataSize,
1224 IN VOID *Data
1225 )
1226 {
1227 VARIABLE_POINTER_TRACK Variable;
1228 EFI_STATUS Status;
1229 VARIABLE_HEADER *NextVariable;
1230 UINTN VarNameSize;
1231 UINTN VarNameOffset;
1232 UINTN VarDataOffset;
1233 UINTN VarSize;
1234 UINT8 State;
1235 BOOLEAN Reclaimed;
1236 UINTN *VolatileOffset;
1237 UINTN *NonVolatileOffset;
1238 EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *Fvb;
1239 BOOLEAN Volatile;
1240 EFI_PHYSICAL_ADDRESS Point;
1241 UINTN ScratchSize;
1242 UINTN NonVolatileVarableStoreSize;
1243
1244 //
1245 // Check input parameters
1246 //
1247 if (VariableName == NULL || VariableName[0] == 0 || VendorGuid == NULL) {
1248 return EFI_INVALID_PARAMETER;
1249 }
1250 //
1251 // Make sure if runtime bit is set, boot service bit is set also
1252 //
1253 if ((Attributes & (EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS)) == EFI_VARIABLE_RUNTIME_ACCESS) {
1254 return EFI_INVALID_PARAMETER;
1255 }
1256
1257 //
1258 // The size of the VariableName, including the Unicode Null in bytes plus
1259 // the DataSize is limited to maximum size of FixedPcdGet32(PcdMaxHardwareErrorVariableSize)
1260 // bytes for HwErrRec, and FixedPcdGet32(PcdMaxVariableSize) bytes for the others.
1261 //
1262 if ((Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == EFI_VARIABLE_HARDWARE_ERROR_RECORD) {
1263 if ((DataSize > FixedPcdGet32(PcdMaxHardwareErrorVariableSize)) ||
1264 (sizeof (VARIABLE_HEADER) + StrSize (VariableName) + DataSize > FixedPcdGet32(PcdMaxHardwareErrorVariableSize))) {
1265 return EFI_INVALID_PARAMETER;
1266 }
1267 } else {
1268 //
1269 // The size of the VariableName, including the Unicode Null in bytes plus
1270 // the DataSize is limited to maximum size of FixedPcdGet32(PcdMaxVariableSize) bytes.
1271 //
1272 if ((DataSize > FixedPcdGet32(PcdMaxVariableSize)) ||
1273 (sizeof (VARIABLE_HEADER) + StrSize (VariableName) + DataSize > FixedPcdGet32(PcdMaxVariableSize))) {
1274 return EFI_INVALID_PARAMETER;
1275 }
1276 }
1277
1278 AcquireLockOnlyAtBootTime(&mVariableModuleGlobal->VariableGlobal.VariableServicesLock);
1279
1280 Reclaimed = FALSE;
1281 Fvb = mVariableModuleGlobal->FvbInstance;
1282 VolatileOffset = &mVariableModuleGlobal->VolatileLastVariableOffset;
1283
1284 //
1285 // Consider reentrant in MCA/INIT/NMI. It needs be reupdated;
1286 //
1287 if (1 < InterlockedIncrement (&mVariableModuleGlobal->VariableGlobal.ReentrantState)) {
1288 Point = mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase;;
1289 //
1290 // Parse non-volatile variable data and get last variable offset
1291 //
1292 NextVariable = GetStartPointer ((VARIABLE_STORE_HEADER *) (UINTN) Point);
1293 while (IsValidVariableHeader (NextVariable)) {
1294 NextVariable = GetNextVariablePtr (NextVariable);
1295 }
1296 mVariableModuleGlobal->NonVolatileLastVariableOffset = (UINTN) NextVariable - (UINTN) Point;
1297 }
1298
1299 NonVolatileOffset = &mVariableModuleGlobal->NonVolatileLastVariableOffset;
1300
1301
1302 //
1303 // Check whether the input variable is already existed
1304 //
1305
1306 Status = FindVariable (VariableName, VendorGuid, &Variable, &mVariableModuleGlobal->VariableGlobal);
1307 if (Status == EFI_SUCCESS && Variable.CurrPtr != NULL) {
1308 //
1309 // Update/Delete existing variable
1310 //
1311 Volatile = Variable.Volatile;
1312
1313 if (EfiAtRuntime ()) {
1314 //
1315 // If EfiAtRuntime and the variable is Volatile and Runtime Access,
1316 // the volatile is ReadOnly, and SetVariable should be aborted and
1317 // return EFI_WRITE_PROTECTED.
1318 //
1319 if (Variable.Volatile) {
1320 Status = EFI_WRITE_PROTECTED;
1321 goto Done;
1322 }
1323 //
1324 // Only variable have NV attribute can be updated/deleted in Runtime
1325 //
1326 if ((Variable.CurrPtr->Attributes & EFI_VARIABLE_NON_VOLATILE) == 0) {
1327 Status = EFI_INVALID_PARAMETER;
1328 goto Done;
1329 }
1330 }
1331 //
1332 // Setting a data variable with no access, or zero DataSize attributes
1333 // specified causes it to be deleted.
1334 //
1335 if (DataSize == 0 || (Attributes & (EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS)) == 0) {
1336 State = Variable.CurrPtr->State;
1337 State &= VAR_DELETED;
1338
1339 Status = UpdateVariableStore (
1340 &mVariableModuleGlobal->VariableGlobal,
1341 Variable.Volatile,
1342 FALSE,
1343 Fvb,
1344 (UINTN) &Variable.CurrPtr->State,
1345 sizeof (UINT8),
1346 &State
1347 );
1348 if (!EFI_ERROR (Status)) {
1349 UpdateVariableInfo (VariableName, VendorGuid, Volatile, FALSE, FALSE, TRUE, FALSE);
1350 UpdateVariableCache (VariableName, VendorGuid, Attributes, DataSize, Data);
1351 }
1352 goto Done;
1353 }
1354 //
1355 // If the variable is marked valid and the same data has been passed in
1356 // then return to the caller immediately.
1357 //
1358 if (DataSizeOfVariable (Variable.CurrPtr) == DataSize &&
1359 (CompareMem (Data, GetVariableDataPtr (Variable.CurrPtr), DataSize) == 0)) {
1360
1361 UpdateVariableInfo (VariableName, VendorGuid, Volatile, FALSE, TRUE, FALSE, FALSE);
1362 Status = EFI_SUCCESS;
1363 goto Done;
1364 } else if ((Variable.CurrPtr->State == VAR_ADDED) ||
1365 (Variable.CurrPtr->State == (VAR_ADDED & VAR_IN_DELETED_TRANSITION))) {
1366
1367 //
1368 // Mark the old variable as in delete transition
1369 //
1370 State = Variable.CurrPtr->State;
1371 State &= VAR_IN_DELETED_TRANSITION;
1372
1373 Status = UpdateVariableStore (
1374 &mVariableModuleGlobal->VariableGlobal,
1375 Variable.Volatile,
1376 FALSE,
1377 Fvb,
1378 (UINTN) &Variable.CurrPtr->State,
1379 sizeof (UINT8),
1380 &State
1381 );
1382 if (EFI_ERROR (Status)) {
1383 goto Done;
1384 }
1385 }
1386 } else if (Status == EFI_NOT_FOUND) {
1387 //
1388 // Create a new variable
1389 //
1390
1391 //
1392 // Make sure we are trying to create a new variable.
1393 // Setting a data variable with no access, or zero DataSize attributes means to delete it.
1394 //
1395 if (DataSize == 0 || (Attributes & (EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS)) == 0) {
1396 Status = EFI_NOT_FOUND;
1397 goto Done;
1398 }
1399
1400 //
1401 // Only variable have NV|RT attribute can be created in Runtime
1402 //
1403 if (EfiAtRuntime () &&
1404 (((Attributes & EFI_VARIABLE_RUNTIME_ACCESS) == 0) || ((Attributes & EFI_VARIABLE_NON_VOLATILE) == 0))) {
1405 Status = EFI_INVALID_PARAMETER;
1406 goto Done;
1407 }
1408 } else {
1409 //
1410 // Status should be EFI_INVALID_PARAMETER here according to return status of FindVariable().
1411 //
1412 ASSERT (Status == EFI_INVALID_PARAMETER);
1413 goto Done;
1414 }
1415
1416 //
1417 // Function part - create a new variable and copy the data.
1418 // Both update a variable and create a variable will come here.
1419 //
1420 // Tricky part: Use scratch data area at the end of volatile variable store
1421 // as a temporary storage.
1422 //
1423 NextVariable = GetEndPointer ((VARIABLE_STORE_HEADER *) ((UINTN) mVariableModuleGlobal->VariableGlobal.VolatileVariableBase));
1424 ScratchSize = MAX(FixedPcdGet32(PcdMaxVariableSize), FixedPcdGet32(PcdMaxHardwareErrorVariableSize));
1425
1426 SetMem (NextVariable, ScratchSize, 0xff);
1427
1428 NextVariable->StartId = VARIABLE_DATA;
1429 NextVariable->Attributes = Attributes;
1430 //
1431 // NextVariable->State = VAR_ADDED;
1432 //
1433 NextVariable->Reserved = 0;
1434 VarNameOffset = sizeof (VARIABLE_HEADER);
1435 VarNameSize = StrSize (VariableName);
1436 CopyMem (
1437 (UINT8 *) ((UINTN) NextVariable + VarNameOffset),
1438 VariableName,
1439 VarNameSize
1440 );
1441 VarDataOffset = VarNameOffset + VarNameSize + GET_PAD_SIZE (VarNameSize);
1442 CopyMem (
1443 (UINT8 *) ((UINTN) NextVariable + VarDataOffset),
1444 Data,
1445 DataSize
1446 );
1447 CopyMem (&NextVariable->VendorGuid, VendorGuid, sizeof (EFI_GUID));
1448 //
1449 // There will be pad bytes after Data, the NextVariable->NameSize and
1450 // NextVariable->DataSize should not include pad size so that variable
1451 // service can get actual size in GetVariable
1452 //
1453 NextVariable->NameSize = (UINT32)VarNameSize;
1454 NextVariable->DataSize = (UINT32)DataSize;
1455
1456 //
1457 // The actual size of the variable that stores in storage should
1458 // include pad size.
1459 //
1460 VarSize = VarDataOffset + DataSize + GET_PAD_SIZE (DataSize);
1461 if ((Attributes & EFI_VARIABLE_NON_VOLATILE) != 0) {
1462 //
1463 // Create a nonvolatile variable
1464 //
1465 Volatile = FALSE;
1466 NonVolatileVarableStoreSize = ((VARIABLE_STORE_HEADER *)(UINTN)(mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase))->Size;
1467 if ((((Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) != 0)
1468 && ((VarSize + mVariableModuleGlobal->HwErrVariableTotalSize) > FixedPcdGet32(PcdHwErrStorageSize)))
1469 || (((Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == 0)
1470 && ((VarSize + mVariableModuleGlobal->CommonVariableTotalSize) > NonVolatileVarableStoreSize - sizeof (VARIABLE_STORE_HEADER) - FixedPcdGet32(PcdHwErrStorageSize)))) {
1471 if (EfiAtRuntime ()) {
1472 Status = EFI_OUT_OF_RESOURCES;
1473 goto Done;
1474 }
1475 //
1476 // Perform garbage collection & reclaim operation
1477 //
1478 Status = Reclaim (mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase, NonVolatileOffset, FALSE, Variable.CurrPtr);
1479 if (EFI_ERROR (Status)) {
1480 goto Done;
1481 }
1482 //
1483 // If still no enough space, return out of resources
1484 //
1485 if ((((Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) != 0)
1486 && ((VarSize + mVariableModuleGlobal->HwErrVariableTotalSize) > FixedPcdGet32(PcdHwErrStorageSize)))
1487 || (((Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == 0)
1488 && ((VarSize + mVariableModuleGlobal->CommonVariableTotalSize) > NonVolatileVarableStoreSize - sizeof (VARIABLE_STORE_HEADER) - FixedPcdGet32(PcdHwErrStorageSize)))) {
1489 Status = EFI_OUT_OF_RESOURCES;
1490 goto Done;
1491 }
1492
1493 Reclaimed = TRUE;
1494 }
1495 //
1496 // Three steps
1497 // 1. Write variable header
1498 // 2. Set variable state to header valid
1499 // 3. Write variable data
1500 // 4. Set variable state to valid
1501 //
1502 //
1503 // Step 1:
1504 //
1505 Status = UpdateVariableStore (
1506 &mVariableModuleGlobal->VariableGlobal,
1507 FALSE,
1508 TRUE,
1509 Fvb,
1510 *NonVolatileOffset,
1511 sizeof (VARIABLE_HEADER),
1512 (UINT8 *) NextVariable
1513 );
1514
1515 if (EFI_ERROR (Status)) {
1516 goto Done;
1517 }
1518
1519 //
1520 // Step 2:
1521 //
1522 NextVariable->State = VAR_HEADER_VALID_ONLY;
1523 Status = UpdateVariableStore (
1524 &mVariableModuleGlobal->VariableGlobal,
1525 FALSE,
1526 TRUE,
1527 Fvb,
1528 *NonVolatileOffset,
1529 sizeof (VARIABLE_HEADER),
1530 (UINT8 *) NextVariable
1531 );
1532
1533 if (EFI_ERROR (Status)) {
1534 goto Done;
1535 }
1536 //
1537 // Step 3:
1538 //
1539 Status = UpdateVariableStore (
1540 &mVariableModuleGlobal->VariableGlobal,
1541 FALSE,
1542 TRUE,
1543 Fvb,
1544 *NonVolatileOffset + sizeof (VARIABLE_HEADER),
1545 (UINT32) VarSize - sizeof (VARIABLE_HEADER),
1546 (UINT8 *) NextVariable + sizeof (VARIABLE_HEADER)
1547 );
1548
1549 if (EFI_ERROR (Status)) {
1550 goto Done;
1551 }
1552 //
1553 // Step 4:
1554 //
1555 NextVariable->State = VAR_ADDED;
1556 Status = UpdateVariableStore (
1557 &mVariableModuleGlobal->VariableGlobal,
1558 FALSE,
1559 TRUE,
1560 Fvb,
1561 *NonVolatileOffset,
1562 sizeof (VARIABLE_HEADER),
1563 (UINT8 *) NextVariable
1564 );
1565
1566 if (EFI_ERROR (Status)) {
1567 goto Done;
1568 }
1569
1570 *NonVolatileOffset = HEADER_ALIGN (*NonVolatileOffset + VarSize);
1571
1572 if ((Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) != 0) {
1573 mVariableModuleGlobal->HwErrVariableTotalSize += HEADER_ALIGN (VarSize);
1574 } else {
1575 mVariableModuleGlobal->CommonVariableTotalSize += HEADER_ALIGN (VarSize);
1576 }
1577 } else {
1578 //
1579 // Create a volatile variable
1580 //
1581 Volatile = TRUE;
1582
1583 if ((UINT32) (VarSize +*VolatileOffset) >
1584 ((VARIABLE_STORE_HEADER *) ((UINTN) (mVariableModuleGlobal->VariableGlobal.VolatileVariableBase)))->Size) {
1585 //
1586 // Perform garbage collection & reclaim operation
1587 //
1588 Status = Reclaim (mVariableModuleGlobal->VariableGlobal.VolatileVariableBase, VolatileOffset, TRUE, Variable.CurrPtr);
1589 if (EFI_ERROR (Status)) {
1590 goto Done;
1591 }
1592 //
1593 // If still no enough space, return out of resources
1594 //
1595 if ((UINT32) (VarSize +*VolatileOffset) >
1596 ((VARIABLE_STORE_HEADER *) ((UINTN) (mVariableModuleGlobal->VariableGlobal.VolatileVariableBase)))->Size
1597 ) {
1598 Status = EFI_OUT_OF_RESOURCES;
1599 goto Done;
1600 }
1601
1602 Reclaimed = TRUE;
1603 }
1604
1605 NextVariable->State = VAR_ADDED;
1606 Status = UpdateVariableStore (
1607 &mVariableModuleGlobal->VariableGlobal,
1608 TRUE,
1609 TRUE,
1610 Fvb,
1611 *VolatileOffset,
1612 (UINT32) VarSize,
1613 (UINT8 *) NextVariable
1614 );
1615
1616 if (EFI_ERROR (Status)) {
1617 goto Done;
1618 }
1619
1620 *VolatileOffset = HEADER_ALIGN (*VolatileOffset + VarSize);
1621 }
1622 //
1623 // Mark the old variable as deleted
1624 //
1625 if (!Reclaimed && !EFI_ERROR (Status) && Variable.CurrPtr != NULL) {
1626 State = Variable.CurrPtr->State;
1627 State &= VAR_DELETED;
1628
1629 Status = UpdateVariableStore (
1630 &mVariableModuleGlobal->VariableGlobal,
1631 Variable.Volatile,
1632 FALSE,
1633 Fvb,
1634 (UINTN) &Variable.CurrPtr->State,
1635 sizeof (UINT8),
1636 &State
1637 );
1638
1639 if (!EFI_ERROR (Status)) {
1640 UpdateVariableInfo (VariableName, VendorGuid, Volatile, FALSE, TRUE, FALSE, FALSE);
1641 UpdateVariableCache (VariableName, VendorGuid, Attributes, DataSize, Data);
1642 }
1643 goto Done;
1644 }
1645
1646 Status = EFI_SUCCESS;
1647 UpdateVariableInfo (VariableName, VendorGuid, Volatile, FALSE, TRUE, FALSE, FALSE);
1648 UpdateVariableCache (VariableName, VendorGuid, Attributes, DataSize, Data);
1649
1650 Done:
1651 InterlockedDecrement (&mVariableModuleGlobal->VariableGlobal.ReentrantState);
1652 ReleaseLockOnlyAtBootTime (&mVariableModuleGlobal->VariableGlobal.VariableServicesLock);
1653
1654 return Status;
1655 }
1656
1657 /**
1658
1659 This code returns information about the EFI variables.
1660
1661 @param Attributes Attributes bitmask to specify the type of variables
1662 on which to return information.
1663 @param MaximumVariableStorageSize Pointer to the maximum size of the storage space available
1664 for the EFI variables associated with the attributes specified.
1665 @param RemainingVariableStorageSize Pointer to the remaining size of the storage space available
1666 for EFI variables associated with the attributes specified.
1667 @param MaximumVariableSize Pointer to the maximum size of an individual EFI variables
1668 associated with the attributes specified.
1669
1670 @return EFI_INVALID_PARAMETER An invalid combination of attribute bits was supplied.
1671 @return EFI_SUCCESS Query successfully.
1672 @return EFI_UNSUPPORTED The attribute is not supported on this platform.
1673
1674 **/
1675 EFI_STATUS
1676 EFIAPI
1677 RuntimeServiceQueryVariableInfo (
1678 IN UINT32 Attributes,
1679 OUT UINT64 *MaximumVariableStorageSize,
1680 OUT UINT64 *RemainingVariableStorageSize,
1681 OUT UINT64 *MaximumVariableSize
1682 )
1683 {
1684 VARIABLE_HEADER *Variable;
1685 VARIABLE_HEADER *NextVariable;
1686 UINT64 VariableSize;
1687 VARIABLE_STORE_HEADER *VariableStoreHeader;
1688 UINT64 CommonVariableTotalSize;
1689 UINT64 HwErrVariableTotalSize;
1690
1691 CommonVariableTotalSize = 0;
1692 HwErrVariableTotalSize = 0;
1693
1694 if(MaximumVariableStorageSize == NULL || RemainingVariableStorageSize == NULL || MaximumVariableSize == NULL || Attributes == 0) {
1695 return EFI_INVALID_PARAMETER;
1696 }
1697
1698 if((Attributes & (EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_HARDWARE_ERROR_RECORD)) == 0) {
1699 //
1700 // Make sure the Attributes combination is supported by the platform.
1701 //
1702 return EFI_UNSUPPORTED;
1703 } else if ((Attributes & (EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS)) == EFI_VARIABLE_RUNTIME_ACCESS) {
1704 //
1705 // Make sure if runtime bit is set, boot service bit is set also.
1706 //
1707 return EFI_INVALID_PARAMETER;
1708 } else if (EfiAtRuntime () && ((Attributes & EFI_VARIABLE_RUNTIME_ACCESS) == 0)) {
1709 //
1710 // Make sure RT Attribute is set if we are in Runtime phase.
1711 //
1712 return EFI_INVALID_PARAMETER;
1713 } else if ((Attributes & (EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_HARDWARE_ERROR_RECORD)) == EFI_VARIABLE_HARDWARE_ERROR_RECORD) {
1714 //
1715 // Make sure Hw Attribute is set with NV.
1716 //
1717 return EFI_INVALID_PARAMETER;
1718 }
1719
1720 AcquireLockOnlyAtBootTime(&mVariableModuleGlobal->VariableGlobal.VariableServicesLock);
1721
1722 if((Attributes & EFI_VARIABLE_NON_VOLATILE) == 0) {
1723 //
1724 // Query is Volatile related.
1725 //
1726 VariableStoreHeader = (VARIABLE_STORE_HEADER *) ((UINTN) mVariableModuleGlobal->VariableGlobal.VolatileVariableBase);
1727 } else {
1728 //
1729 // Query is Non-Volatile related.
1730 //
1731 VariableStoreHeader = (VARIABLE_STORE_HEADER *) ((UINTN) mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase);
1732 }
1733
1734 //
1735 // Now let's fill *MaximumVariableStorageSize *RemainingVariableStorageSize
1736 // with the storage size (excluding the storage header size).
1737 //
1738 *MaximumVariableStorageSize = VariableStoreHeader->Size - sizeof (VARIABLE_STORE_HEADER);
1739
1740 //
1741 // Harware error record variable needs larger size.
1742 //
1743 if ((Attributes & (EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_HARDWARE_ERROR_RECORD)) == (EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_HARDWARE_ERROR_RECORD)) {
1744 *MaximumVariableStorageSize = FixedPcdGet32(PcdHwErrStorageSize);
1745 *MaximumVariableSize = FixedPcdGet32(PcdMaxHardwareErrorVariableSize) - sizeof (VARIABLE_HEADER);
1746 } else {
1747 if ((Attributes & EFI_VARIABLE_NON_VOLATILE) != 0) {
1748 ASSERT (FixedPcdGet32(PcdHwErrStorageSize) < VariableStoreHeader->Size);
1749 *MaximumVariableStorageSize = VariableStoreHeader->Size - sizeof (VARIABLE_STORE_HEADER) - FixedPcdGet32(PcdHwErrStorageSize);
1750 }
1751
1752 //
1753 // Let *MaximumVariableSize be FixedPcdGet32(PcdMaxVariableSize) with the exception of the variable header size.
1754 //
1755 *MaximumVariableSize = FixedPcdGet32(PcdMaxVariableSize) - sizeof (VARIABLE_HEADER);
1756 }
1757
1758 //
1759 // Point to the starting address of the variables.
1760 //
1761 Variable = GetStartPointer (VariableStoreHeader);
1762
1763 //
1764 // Now walk through the related variable store.
1765 //
1766 while ((Variable < GetEndPointer (VariableStoreHeader)) && IsValidVariableHeader (Variable)) {
1767 NextVariable = GetNextVariablePtr (Variable);
1768 VariableSize = (UINT64) (UINTN) NextVariable - (UINT64) (UINTN) Variable;
1769
1770 if (EfiAtRuntime ()) {
1771 //
1772 // we don't take the state of the variables in mind
1773 // when calculating RemainingVariableStorageSize,
1774 // since the space occupied by variables not marked with
1775 // VAR_ADDED is not allowed to be reclaimed in Runtime.
1776 //
1777 if ((NextVariable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == EFI_VARIABLE_HARDWARE_ERROR_RECORD) {
1778 HwErrVariableTotalSize += VariableSize;
1779 } else {
1780 CommonVariableTotalSize += VariableSize;
1781 }
1782 } else {
1783 //
1784 // Only care about Variables with State VAR_ADDED,because
1785 // the space not marked as VAR_ADDED is reclaimable now.
1786 //
1787 if (Variable->State == VAR_ADDED) {
1788 if ((NextVariable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == EFI_VARIABLE_HARDWARE_ERROR_RECORD) {
1789 HwErrVariableTotalSize += VariableSize;
1790 } else {
1791 CommonVariableTotalSize += VariableSize;
1792 }
1793 }
1794 }
1795
1796 //
1797 // Go to the next one
1798 //
1799 Variable = NextVariable;
1800 }
1801
1802 if ((Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == EFI_VARIABLE_HARDWARE_ERROR_RECORD){
1803 *RemainingVariableStorageSize = *MaximumVariableStorageSize - HwErrVariableTotalSize;
1804 }else {
1805 *RemainingVariableStorageSize = *MaximumVariableStorageSize - CommonVariableTotalSize;
1806 }
1807
1808 if (*RemainingVariableStorageSize < sizeof (VARIABLE_HEADER)) {
1809 *MaximumVariableSize = 0;
1810 } else if ((*RemainingVariableStorageSize - sizeof (VARIABLE_HEADER)) < *MaximumVariableSize) {
1811 *MaximumVariableSize = *RemainingVariableStorageSize - sizeof (VARIABLE_HEADER);
1812 }
1813
1814 ReleaseLockOnlyAtBootTime (&mVariableModuleGlobal->VariableGlobal.VariableServicesLock);
1815 return EFI_SUCCESS;
1816 }
1817
1818
1819 /**
1820 Notification function of EVT_GROUP_READY_TO_BOOT event group.
1821
1822 This is a notification function registered on EVT_GROUP_READY_TO_BOOT event group.
1823 When the Boot Manager is about to load and execute a boot option, it reclaims variable
1824 storage if free size is below the threshold.
1825
1826 @param Event Event whose notification function is being invoked
1827 @param Context Pointer to the notification function's context
1828
1829 **/
1830 VOID
1831 EFIAPI
1832 ReclaimForOS(
1833 EFI_EVENT Event,
1834 VOID *Context
1835 )
1836 {
1837 EFI_STATUS Status;
1838 UINTN CommonVariableSpace;
1839 UINTN RemainingCommonVariableSpace;
1840 UINTN RemainingHwErrVariableSpace;
1841
1842 Status = EFI_SUCCESS;
1843
1844 CommonVariableSpace = ((VARIABLE_STORE_HEADER *) ((UINTN) (mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase)))->Size - sizeof (VARIABLE_STORE_HEADER) - PcdGet32(PcdHwErrStorageSize); //Allowable max size of common variable storage space
1845
1846 RemainingCommonVariableSpace = CommonVariableSpace - mVariableModuleGlobal->CommonVariableTotalSize;
1847
1848 RemainingHwErrVariableSpace = PcdGet32 (PcdHwErrStorageSize) - mVariableModuleGlobal->HwErrVariableTotalSize;
1849 //
1850 // Check if the free area is blow a threshold
1851 //
1852 if ((RemainingCommonVariableSpace < PcdGet32 (PcdMaxVariableSize))
1853 || (RemainingHwErrVariableSpace < PcdGet32 (PcdMaxHardwareErrorVariableSize))){
1854 Status = Reclaim (
1855 mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase,
1856 &mVariableModuleGlobal->NonVolatileLastVariableOffset,
1857 FALSE,
1858 NULL
1859 );
1860 ASSERT_EFI_ERROR (Status);
1861 }
1862 }
1863
1864 /**
1865 Initializes variable store area for non-volatile and volatile variable.
1866
1867 @param SystemTable The pointer of EFI_SYSTEM_TABLE.
1868
1869 @retval EFI_SUCCESS Function successfully executed.
1870 @retval EFI_OUT_OF_RESOURCES Fail to allocate enough memory resource.
1871
1872 **/
1873 EFI_STATUS
1874 VariableCommonInitialize (
1875 IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *FvbProtocol
1876 )
1877 {
1878 EFI_STATUS Status;
1879 VARIABLE_STORE_HEADER *VolatileVariableStore;
1880 VARIABLE_STORE_HEADER *VariableStoreHeader;
1881 VARIABLE_HEADER *NextVariable;
1882 EFI_PHYSICAL_ADDRESS TempVariableStoreHeader;
1883 EFI_GCD_MEMORY_SPACE_DESCRIPTOR GcdDescriptor;
1884 EFI_PHYSICAL_ADDRESS BaseAddress;
1885 UINT64 Length;
1886 UINTN Index;
1887 UINT8 Data;
1888 EFI_PHYSICAL_ADDRESS VariableStoreBase;
1889 UINT64 VariableStoreLength;
1890 EFI_EVENT ReadyToBootEvent;
1891 UINTN ScratchSize;
1892
1893 Status = EFI_SUCCESS;
1894 //
1895 // Allocate runtime memory for variable driver global structure.
1896 //
1897 mVariableModuleGlobal = AllocateRuntimePool (sizeof (VARIABLE_MODULE_GLOBAL));
1898 if (mVariableModuleGlobal == NULL) {
1899 return EFI_OUT_OF_RESOURCES;
1900 }
1901
1902 EfiInitializeLock(&mVariableModuleGlobal->VariableGlobal.VariableServicesLock, TPL_NOTIFY);
1903 mVariableModuleGlobal->VariableGlobal.ReentrantState = 0;
1904 mVariableModuleGlobal->CommonVariableTotalSize = 0;
1905 mVariableModuleGlobal->HwErrVariableTotalSize = 0;
1906
1907 //
1908 // Allocate memory for volatile variable store, note that there is a scratch space to store scratch data.
1909 //
1910 ScratchSize = MAX(FixedPcdGet32(PcdMaxVariableSize), FixedPcdGet32(PcdMaxHardwareErrorVariableSize));
1911 VolatileVariableStore = AllocateRuntimePool (FixedPcdGet32(PcdVariableStoreSize) + ScratchSize);
1912 if (VolatileVariableStore == NULL) {
1913 FreePool (mVariableModuleGlobal);
1914 return EFI_OUT_OF_RESOURCES;
1915 }
1916
1917 SetMem (VolatileVariableStore, FixedPcdGet32(PcdVariableStoreSize) + ScratchSize, 0xff);
1918
1919 //
1920 // Variable Specific Data
1921 //
1922 mVariableModuleGlobal->VariableGlobal.VolatileVariableBase = (EFI_PHYSICAL_ADDRESS) (UINTN) VolatileVariableStore;
1923 mVariableModuleGlobal->VolatileLastVariableOffset = (UINTN) GetStartPointer (VolatileVariableStore) - (UINTN) VolatileVariableStore;
1924 mVariableModuleGlobal->FvbInstance = FvbProtocol;
1925
1926 CopyGuid (&VolatileVariableStore->Signature, &gEfiVariableGuid);
1927 VolatileVariableStore->Size = FixedPcdGet32(PcdVariableStoreSize);
1928 VolatileVariableStore->Format = VARIABLE_STORE_FORMATTED;
1929 VolatileVariableStore->State = VARIABLE_STORE_HEALTHY;
1930 VolatileVariableStore->Reserved = 0;
1931 VolatileVariableStore->Reserved1 = 0;
1932
1933 //
1934 // Get non volatile varaible store
1935 //
1936
1937 TempVariableStoreHeader = (EFI_PHYSICAL_ADDRESS) PcdGet32 (PcdFlashNvStorageVariableBase);
1938 VariableStoreBase = TempVariableStoreHeader + \
1939 (((EFI_FIRMWARE_VOLUME_HEADER *)(UINTN)(TempVariableStoreHeader)) -> HeaderLength);
1940 VariableStoreLength = (UINT64) PcdGet32 (PcdFlashNvStorageVariableSize) - \
1941 (((EFI_FIRMWARE_VOLUME_HEADER *)(UINTN)(TempVariableStoreHeader)) -> HeaderLength);
1942 //
1943 // Mark the variable storage region of the FLASH as RUNTIME
1944 //
1945 BaseAddress = VariableStoreBase & (~EFI_PAGE_MASK);
1946 Length = VariableStoreLength + (VariableStoreBase - BaseAddress);
1947 Length = (Length + EFI_PAGE_SIZE - 1) & (~EFI_PAGE_MASK);
1948
1949 Status = gDS->GetMemorySpaceDescriptor (BaseAddress, &GcdDescriptor);
1950 if (EFI_ERROR (Status)) {
1951 goto Done;
1952 }
1953
1954 Status = gDS->SetMemorySpaceAttributes (
1955 BaseAddress,
1956 Length,
1957 GcdDescriptor.Attributes | EFI_MEMORY_RUNTIME
1958 );
1959 if (EFI_ERROR (Status)) {
1960 goto Done;
1961 }
1962 //
1963 // Get address of non volatile variable store base
1964 //
1965 mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase = VariableStoreBase;
1966 VariableStoreHeader = (VARIABLE_STORE_HEADER *)(UINTN)VariableStoreBase;
1967 if (GetVariableStoreStatus (VariableStoreHeader) == EfiValid) {
1968 if (~VariableStoreHeader->Size == 0) {
1969 Status = UpdateVariableStore (
1970 &mVariableModuleGlobal->VariableGlobal,
1971 FALSE,
1972 FALSE,
1973 mVariableModuleGlobal->FvbInstance,
1974 (UINTN) &VariableStoreHeader->Size,
1975 sizeof (UINT32),
1976 (UINT8 *) &VariableStoreLength
1977 );
1978 //
1979 // As Variables are stored in NV storage, which are slow devices,such as flash.
1980 // Variable operation may skip checking variable program result to improve performance,
1981 // We can assume Variable program is OK through some check point.
1982 // Variable Store Size Setting should be the first Variable write operation,
1983 // We can assume all Read/Write is OK if we can set Variable store size successfully.
1984 // If write fail, we will assert here
1985 //
1986 ASSERT(VariableStoreHeader->Size == VariableStoreLength);
1987
1988 if (EFI_ERROR (Status)) {
1989 goto Done;
1990 }
1991 }
1992
1993 //
1994 // Parse non-volatile variable data and get last variable offset
1995 //
1996 NextVariable = GetStartPointer ((VARIABLE_STORE_HEADER *)(UINTN)VariableStoreBase);
1997 Status = EFI_SUCCESS;
1998
1999 while (IsValidVariableHeader (NextVariable)) {
2000 UINTN VariableSize = 0;
2001 VariableSize = NextVariable->NameSize + NextVariable->DataSize + sizeof (VARIABLE_HEADER);
2002 if ((NextVariable->Attributes & (EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_HARDWARE_ERROR_RECORD)) == (EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_HARDWARE_ERROR_RECORD)) {
2003 mVariableModuleGlobal->HwErrVariableTotalSize += HEADER_ALIGN (VariableSize);
2004 } else {
2005 mVariableModuleGlobal->CommonVariableTotalSize += HEADER_ALIGN (VariableSize);
2006 }
2007
2008 NextVariable = GetNextVariablePtr (NextVariable);
2009 }
2010
2011 mVariableModuleGlobal->NonVolatileLastVariableOffset = (UINTN) NextVariable - (UINTN) VariableStoreBase;
2012
2013 //
2014 // Check if the free area is really free.
2015 //
2016 for (Index = mVariableModuleGlobal->NonVolatileLastVariableOffset; Index < VariableStoreHeader->Size; Index++) {
2017 Data = ((UINT8 *) (UINTN) mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase)[Index];
2018 if (Data != 0xff) {
2019 //
2020 // There must be something wrong in variable store, do reclaim operation.
2021 //
2022 Status = Reclaim (
2023 mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase,
2024 &mVariableModuleGlobal->NonVolatileLastVariableOffset,
2025 FALSE,
2026 NULL
2027 );
2028
2029 if (EFI_ERROR (Status)) {
2030 goto Done;
2031 }
2032
2033 break;
2034 }
2035 }
2036
2037 //
2038 // Register the event handling function to reclaim variable for OS usage.
2039 //
2040 Status = EfiCreateEventReadyToBootEx (
2041 TPL_NOTIFY,
2042 ReclaimForOS,
2043 NULL,
2044 &ReadyToBootEvent
2045 );
2046 } else {
2047 Status = EFI_VOLUME_CORRUPTED;
2048 DEBUG((EFI_D_INFO, "Variable Store header is corrupted\n"));
2049 }
2050
2051 Done:
2052 if (EFI_ERROR (Status)) {
2053 FreePool (mVariableModuleGlobal);
2054 FreePool (VolatileVariableStore);
2055 }
2056
2057 return Status;
2058 }
2059
2060 /**
2061 Notification function of EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE
2062
2063 This is a notification function registered on EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE event.
2064 It convers pointer to new virtual address.
2065
2066 @param Event Event whose notification function is being invoked
2067 @param Context Pointer to the notification function's context
2068
2069 **/
2070 VOID
2071 EFIAPI
2072 VariableClassAddressChangeEvent (
2073 IN EFI_EVENT Event,
2074 IN VOID *Context
2075 )
2076 {
2077 EfiConvertPointer (0x0, (VOID **) &mVariableModuleGlobal->FvbInstance->GetBlockSize);
2078 EfiConvertPointer (0x0, (VOID **) &mVariableModuleGlobal->FvbInstance->GetPhysicalAddress);
2079 EfiConvertPointer (0x0, (VOID **) &mVariableModuleGlobal->FvbInstance->GetAttributes);
2080 EfiConvertPointer (0x0, (VOID **) &mVariableModuleGlobal->FvbInstance->SetAttributes);
2081 EfiConvertPointer (0x0, (VOID **) &mVariableModuleGlobal->FvbInstance->Read);
2082 EfiConvertPointer (0x0, (VOID **) &mVariableModuleGlobal->FvbInstance->Write);
2083 EfiConvertPointer (0x0, (VOID **) &mVariableModuleGlobal->FvbInstance->EraseBlocks);
2084 EfiConvertPointer (0x0, (VOID **) &mVariableModuleGlobal->FvbInstance);
2085 EfiConvertPointer (
2086 0x0,
2087 (VOID **) &mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase
2088 );
2089 EfiConvertPointer (
2090 0x0,
2091 (VOID **) &mVariableModuleGlobal->VariableGlobal.VolatileVariableBase
2092 );
2093 EfiConvertPointer (0x0, (VOID **) &mVariableModuleGlobal);
2094 }
2095
2096 VOID
2097 EFIAPI
2098 FvbNotificationEvent (
2099 IN EFI_EVENT Event,
2100 IN VOID *Context
2101 )
2102 {
2103 EFI_STATUS Status;
2104 EFI_HANDLE *HandleBuffer;
2105 UINTN HandleCount;
2106 UINTN Index;
2107 EFI_PHYSICAL_ADDRESS FvbBaseAddress;
2108 EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *Fvb;
2109 EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader;
2110 EFI_FVB_ATTRIBUTES_2 Attributes;
2111 EFI_SYSTEM_TABLE *SystemTable;
2112 EFI_PHYSICAL_ADDRESS NvStorageVariableBase;
2113
2114 SystemTable = (EFI_SYSTEM_TABLE *)Context;
2115 Fvb = NULL;
2116
2117 //
2118 // Locate all handles of Fvb protocol
2119 //
2120 Status = gBS->LocateHandleBuffer (
2121 ByProtocol,
2122 &gEfiFirmwareVolumeBlockProtocolGuid,
2123 NULL,
2124 &HandleCount,
2125 &HandleBuffer
2126 );
2127 if (EFI_ERROR (Status)) {
2128 return ;
2129 }
2130
2131 //
2132 // Get the FVB to access variable store
2133 //
2134 for (Index = 0; Index < HandleCount; Index += 1, Status = EFI_NOT_FOUND, Fvb = NULL) {
2135 Status = gBS->HandleProtocol (
2136 HandleBuffer[Index],
2137 &gEfiFirmwareVolumeBlockProtocolGuid,
2138 (VOID **) &Fvb
2139 );
2140 if (EFI_ERROR (Status)) {
2141 Status = EFI_NOT_FOUND;
2142 break;
2143 }
2144
2145 //
2146 // Ensure this FVB protocol supported Write operation.
2147 //
2148 Status = Fvb->GetAttributes (Fvb, &Attributes);
2149 if (EFI_ERROR (Status) || ((Attributes & EFI_FVB2_WRITE_STATUS) == 0)) {
2150 continue;
2151 }
2152 //
2153 // Compare the address and select the right one
2154 //
2155 Status = Fvb->GetPhysicalAddress (Fvb, &FvbBaseAddress);
2156 if (EFI_ERROR (Status)) {
2157 continue;
2158 }
2159
2160 FwVolHeader = (EFI_FIRMWARE_VOLUME_HEADER *) ((UINTN) FvbBaseAddress);
2161 NvStorageVariableBase = (EFI_PHYSICAL_ADDRESS) PcdGet32 (PcdFlashNvStorageVariableBase);
2162 if ((NvStorageVariableBase >= FvbBaseAddress) && (NvStorageVariableBase < (FvbBaseAddress + FwVolHeader->FvLength))) {
2163 Status = EFI_SUCCESS;
2164 break;
2165 }
2166 }
2167
2168 FreePool (HandleBuffer);
2169 if (!EFI_ERROR (Status) && Fvb != NULL) {
2170 //
2171 // Close the notify event to avoid install gEfiVariableArchProtocolGuid & gEfiVariableWriteArchProtocolGuid again.
2172 //
2173 Status = gBS->CloseEvent (Event);
2174 ASSERT_EFI_ERROR (Status);
2175
2176 Status = VariableCommonInitialize (Fvb);
2177 ASSERT_EFI_ERROR (Status);
2178
2179 SystemTable->RuntimeServices->GetVariable = RuntimeServiceGetVariable;
2180 SystemTable->RuntimeServices->GetNextVariableName = RuntimeServiceGetNextVariableName;
2181 SystemTable->RuntimeServices->SetVariable = RuntimeServiceSetVariable;
2182 SystemTable->RuntimeServices->QueryVariableInfo = RuntimeServiceQueryVariableInfo;
2183
2184 //
2185 // Now install the Variable Runtime Architectural Protocol on a new handle
2186 //
2187 Status = gBS->InstallMultipleProtocolInterfaces (
2188 &mHandle,
2189 &gEfiVariableArchProtocolGuid, NULL,
2190 &gEfiVariableWriteArchProtocolGuid, NULL,
2191 NULL
2192 );
2193 ASSERT_EFI_ERROR (Status);
2194
2195 Status = gBS->CreateEventEx (
2196 EVT_NOTIFY_SIGNAL,
2197 TPL_NOTIFY,
2198 VariableClassAddressChangeEvent,
2199 NULL,
2200 &gEfiEventVirtualAddressChangeGuid,
2201 &mVirtualAddressChangeEvent
2202 );
2203 ASSERT_EFI_ERROR (Status);
2204 }
2205
2206 }
2207
2208 /**
2209 Variable Driver main entry point. The Variable driver places the 4 EFI
2210 runtime services in the EFI System Table and installs arch protocols
2211 for variable read and write services being availible. It also registers
2212 notification function for EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE event.
2213
2214 @param[in] ImageHandle The firmware allocated handle for the EFI image.
2215 @param[in] SystemTable A pointer to the EFI System Table.
2216
2217 @retval EFI_SUCCESS Variable service successfully initialized.
2218
2219 **/
2220 EFI_STATUS
2221 EFIAPI
2222 VariableServiceInitialize (
2223 IN EFI_HANDLE ImageHandle,
2224 IN EFI_SYSTEM_TABLE *SystemTable
2225 )
2226 {
2227 //
2228 // Register FvbNotificationEvent () notify function.
2229 //
2230 EfiCreateProtocolNotifyEvent (
2231 &gEfiFirmwareVolumeBlockProtocolGuid,
2232 TPL_CALLBACK,
2233 FvbNotificationEvent,
2234 (VOID *)SystemTable,
2235 &mFvbRegistration
2236 );
2237
2238 return EFI_SUCCESS;
2239 }
2240