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