]> git.proxmox.com Git - mirror_edk2.git/blob - DuetPkg/FSVariable/FSVariable.c
1. delete Include/Guid/VariableInfo.h
[mirror_edk2.git] / DuetPkg / FSVariable / FSVariable.c
1 /*++
2
3 Copyright (c) 2006 - 2007, Intel Corporation
4 All rights reserved. This program and the accompanying materials
5 are licensed and made available under the terms and conditions of the BSD License
6 which accompanies this distribution. The full text of the license may be found at
7 http://opensource.org/licenses/bsd-license.php
8
9 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
10 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
11
12 Module Name:
13
14 FSVariable.c
15
16 Abstract:
17
18 Provide support functions for variable services.
19
20 --*/
21
22 #include "FSVariable.h"
23
24 VARIABLE_STORE_HEADER mStoreHeaderTemplate = {
25 gEfiVariableGuid,
26 VOLATILE_VARIABLE_STORE_SIZE,
27 VARIABLE_STORE_FORMATTED,
28 VARIABLE_STORE_HEALTHY,
29 0,
30 0
31 };
32
33 //
34 // Don't use module globals after the SetVirtualAddress map is signaled
35 //
36 VARIABLE_GLOBAL *mGlobal;
37
38 VOID
39 EFIAPI
40 OnVirtualAddressChangeFsv (
41 IN EFI_EVENT Event,
42 IN VOID *Context
43 );
44
45 VOID
46 EFIAPI
47 OnSimpleFileSystemInstall (
48 IN EFI_EVENT Event,
49 IN VOID *Context
50 );
51
52 BOOLEAN
53 IsValidVariableHeader (
54 IN VARIABLE_HEADER *Variable
55 )
56 /*++
57
58 Routine Description:
59
60 This code checks if variable header is valid or not.
61
62 Arguments:
63 Variable Pointer to the Variable Header.
64
65 Returns:
66 TRUE Variable header is valid.
67 FALSE Variable header is not valid.
68
69 --*/
70 {
71 if (Variable == NULL ||
72 Variable->StartId != VARIABLE_DATA ||
73 (sizeof (VARIABLE_HEADER) + Variable->NameSize + Variable->DataSize) > FixedPcdGet32(PcdMaxVariableSize)
74 ) {
75 return FALSE;
76 }
77
78 return TRUE;
79 }
80
81 VARIABLE_STORE_STATUS
82 GetVariableStoreStatus (
83 IN VARIABLE_STORE_HEADER *VarStoreHeader
84 )
85 /*++
86
87 Routine Description:
88
89 This code gets the current status of Variable Store.
90
91 Arguments:
92
93 VarStoreHeader Pointer to the Variable Store Header.
94
95 Returns:
96
97 EfiRaw Variable store status is raw
98 EfiValid Variable store status is valid
99 EfiInvalid Variable store status is invalid
100
101 --*/
102 {
103 if (CompareGuid (&VarStoreHeader->Signature, &mStoreHeaderTemplate.Signature) &&
104 (VarStoreHeader->Format == mStoreHeaderTemplate.Format) &&
105 (VarStoreHeader->State == mStoreHeaderTemplate.State)
106 ) {
107 return EfiValid;
108 } else if (((UINT32 *)(&VarStoreHeader->Signature))[0] == VAR_DEFAULT_VALUE_32 &&
109 ((UINT32 *)(&VarStoreHeader->Signature))[1] == VAR_DEFAULT_VALUE_32 &&
110 ((UINT32 *)(&VarStoreHeader->Signature))[2] == VAR_DEFAULT_VALUE_32 &&
111 ((UINT32 *)(&VarStoreHeader->Signature))[3] == VAR_DEFAULT_VALUE_32 &&
112 VarStoreHeader->Size == VAR_DEFAULT_VALUE_32 &&
113 VarStoreHeader->Format == VAR_DEFAULT_VALUE &&
114 VarStoreHeader->State == VAR_DEFAULT_VALUE
115 ) {
116
117 return EfiRaw;
118 } else {
119 return EfiInvalid;
120 }
121 }
122
123 UINT8 *
124 GetVariableDataPtr (
125 IN VARIABLE_HEADER *Variable
126 )
127 /*++
128
129 Routine Description:
130
131 This code gets the pointer to the variable data.
132
133 Arguments:
134
135 Variable Pointer to the Variable Header.
136
137 Returns:
138
139 UINT8* Pointer to Variable Data
140
141 --*/
142 {
143 //
144 // Be careful about pad size for alignment
145 //
146 return (UINT8 *) ((UINTN) GET_VARIABLE_NAME_PTR (Variable) + Variable->NameSize + GET_PAD_SIZE (Variable->NameSize));
147 }
148
149 VARIABLE_HEADER *
150 GetNextVariablePtr (
151 IN VARIABLE_HEADER *Variable
152 )
153 /*++
154
155 Routine Description:
156
157 This code gets the pointer to the next variable header.
158
159 Arguments:
160
161 Variable Pointer to the Variable Header.
162
163 Returns:
164
165 VARIABLE_HEADER* Pointer to next variable header.
166
167 --*/
168 {
169 if (!IsValidVariableHeader (Variable)) {
170 return NULL;
171 }
172 //
173 // Be careful about pad size for alignment
174 //
175 return (VARIABLE_HEADER *) ((UINTN) GetVariableDataPtr (Variable) + Variable->DataSize + GET_PAD_SIZE (Variable->DataSize));
176 }
177
178 VARIABLE_HEADER *
179 GetEndPointer (
180 IN VARIABLE_STORE_HEADER *VarStoreHeader
181 )
182 /*++
183
184 Routine Description:
185
186 This code gets the pointer to the last variable memory pointer byte
187
188 Arguments:
189
190 VarStoreHeader Pointer to the Variable Store Header.
191
192 Returns:
193
194 VARIABLE_HEADER* Pointer to last unavailable Variable Header
195
196 --*/
197 {
198 //
199 // The end of variable store
200 //
201 return (VARIABLE_HEADER *) ((UINTN) VarStoreHeader + VarStoreHeader->Size);
202 }
203
204 BOOLEAN
205 ExistNewerVariable (
206 IN VARIABLE_HEADER *Variable
207 )
208 /*++
209
210 Routine Description:
211
212 Check if exist newer variable when doing reclaim
213
214 Arguments:
215
216 Variable Pointer to start position
217
218 Returns:
219
220 TRUE - Exists another variable, which is newer than the current one
221 FALSE - Doesn't exist another vairable which is newer than the current one
222
223 --*/
224 {
225 VARIABLE_HEADER *NextVariable;
226 CHAR16 *VariableName;
227 EFI_GUID *VendorGuid;
228
229 VendorGuid = &Variable->VendorGuid;
230 VariableName = GET_VARIABLE_NAME_PTR(Variable);
231
232 NextVariable = GetNextVariablePtr (Variable);
233 while (IsValidVariableHeader (NextVariable)) {
234 if ((NextVariable->State == VAR_ADDED) || (NextVariable->State == (VAR_ADDED & VAR_IN_DELETED_TRANSITION))) {
235 //
236 // If match Guid and Name
237 //
238 if (CompareGuid (VendorGuid, &NextVariable->VendorGuid)) {
239 if (CompareMem (VariableName, GET_VARIABLE_NAME_PTR (NextVariable), StrSize (VariableName)) == 0) {
240 return TRUE;
241 }
242 }
243 }
244 NextVariable = GetNextVariablePtr (NextVariable);
245 }
246 return FALSE;
247 }
248
249 EFI_STATUS
250 Reclaim (
251 IN VARIABLE_STORAGE_TYPE StorageType,
252 IN VARIABLE_HEADER *CurrentVariable OPTIONAL
253 )
254 /*++
255
256 Routine Description:
257
258 Variable store garbage collection and reclaim operation
259
260 Arguments:
261
262 IsVolatile The variable store is volatile or not,
263 if it is non-volatile, need FTW
264 CurrentVairable If it is not NULL, it means not to process
265 current variable for Reclaim.
266
267 Returns:
268
269 EFI STATUS
270
271 --*/
272 {
273 VARIABLE_HEADER *Variable;
274 VARIABLE_HEADER *NextVariable;
275 VARIABLE_STORE_HEADER *VariableStoreHeader;
276 UINT8 *ValidBuffer;
277 UINTN ValidBufferSize;
278 UINTN VariableSize;
279 UINT8 *CurrPtr;
280 EFI_STATUS Status;
281
282 VariableStoreHeader = (VARIABLE_STORE_HEADER *) mGlobal->VariableBase[StorageType];
283
284 //
285 // Start Pointers for the variable.
286 //
287 Variable = (VARIABLE_HEADER *) (VariableStoreHeader + 1);
288
289
290 //
291 // To make the reclaim, here we just allocate a memory that equal to the original memory
292 //
293 ValidBufferSize = sizeof (VARIABLE_STORE_HEADER) + VariableStoreHeader->Size;
294
295 Status = gBS->AllocatePool (
296 EfiBootServicesData,
297 ValidBufferSize,
298 (VOID**) &ValidBuffer
299 );
300 if (EFI_ERROR (Status)) {
301 return Status;
302 }
303
304 CurrPtr = ValidBuffer;
305
306 //
307 // Copy variable store header
308 //
309 CopyMem (CurrPtr, VariableStoreHeader, sizeof (VARIABLE_STORE_HEADER));
310 CurrPtr += sizeof (VARIABLE_STORE_HEADER);
311
312 //
313 // Start Pointers for the variable.
314 //
315 Variable = (VARIABLE_HEADER *) (VariableStoreHeader + 1);
316
317
318 ValidBufferSize = sizeof (VARIABLE_STORE_HEADER);
319 while (IsValidVariableHeader (Variable)) {
320 NextVariable = GetNextVariablePtr (Variable);
321 //
322 // State VAR_ADDED or VAR_IN_DELETED_TRANSITION are to kept,
323 // The CurrentVariable, is also saved, as SetVariable may fail due to lack of space
324 //
325 if (Variable->State == VAR_ADDED) {
326 VariableSize = (UINTN) NextVariable - (UINTN) Variable;
327 CopyMem (CurrPtr, (UINT8 *) Variable, VariableSize);
328 ValidBufferSize += VariableSize;
329 CurrPtr += VariableSize;
330 } else if (Variable->State == (VAR_ADDED & VAR_IN_DELETED_TRANSITION)) {
331 //
332 // As variables that with the same guid and name may exist in NV due to power failure during SetVariable,
333 // we will only save the latest valid one
334 //
335 if (!ExistNewerVariable(Variable)) {
336 VariableSize = (UINTN) NextVariable - (UINTN) Variable;
337 CopyMem (CurrPtr, (UINT8 *) Variable, VariableSize);
338 //
339 // If CurrentVariable == Variable, mark as VAR_IN_DELETED_TRANSITION
340 //
341 if (Variable != CurrentVariable){
342 ((VARIABLE_HEADER *)CurrPtr)->State = VAR_ADDED;
343 }
344 CurrPtr += VariableSize;
345 ValidBufferSize += VariableSize;
346 }
347 }
348 Variable = NextVariable;
349 }
350
351 //
352 // TODO: cannot restore to original state, basic FTW needed
353 //
354 Status = mGlobal->VariableStore[StorageType]->Erase (
355 mGlobal->VariableStore[StorageType]
356 );
357 Status = mGlobal->VariableStore[StorageType]->Write (
358 mGlobal->VariableStore[StorageType],
359 0,
360 ValidBufferSize,
361 ValidBuffer
362 );
363
364 // ASSERT_EFI_ERROR (Status);
365
366 mGlobal->LastVariableOffset[StorageType] = ValidBufferSize;
367 gBS->FreePool (ValidBuffer);
368
369 return Status;
370 }
371
372 EFI_STATUS
373 FindVariable (
374 IN CHAR16 *VariableName,
375 IN EFI_GUID *VendorGuid,
376 OUT VARIABLE_POINTER_TRACK *PtrTrack
377 )
378 /*++
379
380 Routine Description:
381
382 This code finds variable in storage blocks (Volatile or Non-Volatile)
383
384 Arguments:
385
386 VariableName Name of the variable to be found
387 VendorGuid Vendor GUID to be found.
388 PtrTrack Variable Track Pointer structure that contains
389 Variable Information.
390 Contains the pointer of Variable header.
391
392 Returns:
393
394 EFI_INVALID_PARAMETER - Invalid parameter
395 EFI_SUCCESS - Find the specified variable
396 EFI_NOT_FOUND - Not found
397
398 --*/
399 {
400 VARIABLE_HEADER *Variable;
401 VARIABLE_STORE_HEADER *VariableStoreHeader;
402 UINTN Index;
403 VARIABLE_HEADER *InDeleteVariable;
404 UINTN InDeleteIndex;
405 VARIABLE_HEADER *InDeleteStartPtr;
406 VARIABLE_HEADER *InDeleteEndPtr;
407
408 if (VariableName[0] != 0 && VendorGuid == NULL) {
409 return EFI_INVALID_PARAMETER;
410 }
411
412 InDeleteVariable = NULL;
413 InDeleteIndex = (UINTN)-1;
414 InDeleteStartPtr = NULL;
415 InDeleteEndPtr = NULL;
416
417 for (Index = 0; Index < MaxType; Index ++) {
418 //
419 // 0: Non-Volatile, 1: Volatile
420 //
421 VariableStoreHeader = (VARIABLE_STORE_HEADER *) mGlobal->VariableBase[Index];
422
423 //
424 // Start Pointers for the variable.
425 // Actual Data Pointer where data can be written.
426 //
427 Variable = (VARIABLE_HEADER *) (VariableStoreHeader + 1);
428
429 //
430 // Find the variable by walk through non-volatile and volatile variable store
431 //
432 PtrTrack->StartPtr = Variable;
433 PtrTrack->EndPtr = GetEndPointer (VariableStoreHeader);
434
435 while (IsValidVariableHeader (Variable) && (Variable < PtrTrack->EndPtr)) {
436 if (Variable->State == VAR_ADDED) {
437 if (!EfiAtRuntime () || (Variable->Attributes & EFI_VARIABLE_RUNTIME_ACCESS)) {
438 if (VariableName[0] == 0) {
439 PtrTrack->CurrPtr = Variable;
440 PtrTrack->Type = (VARIABLE_STORAGE_TYPE) Index;
441 return EFI_SUCCESS;
442 } else {
443 if (CompareGuid (VendorGuid, &Variable->VendorGuid)) {
444 if (!CompareMem (VariableName, GET_VARIABLE_NAME_PTR (Variable), StrSize (VariableName))) {
445 PtrTrack->CurrPtr = Variable;
446 PtrTrack->Type = (VARIABLE_STORAGE_TYPE) Index;
447 return EFI_SUCCESS;
448 }
449 }
450 }
451 }
452 } else if (Variable->State == (VAR_ADDED & VAR_IN_DELETED_TRANSITION)) {
453 //
454 // VAR_IN_DELETED_TRANSITION should also be checked.
455 //
456 if (!EfiAtRuntime () || (Variable->Attributes & EFI_VARIABLE_RUNTIME_ACCESS)) {
457 if (VariableName[0] == 0) {
458 InDeleteVariable = Variable;
459 InDeleteIndex = Index;
460 InDeleteStartPtr = PtrTrack->StartPtr;
461 InDeleteEndPtr = PtrTrack->EndPtr;
462 } else {
463 if (CompareGuid (VendorGuid, &Variable->VendorGuid)) {
464 if (!CompareMem (VariableName, GET_VARIABLE_NAME_PTR (Variable), StrSize (VariableName))) {
465 InDeleteVariable = Variable;
466 InDeleteIndex = Index;
467 InDeleteStartPtr = PtrTrack->StartPtr;
468 InDeleteEndPtr = PtrTrack->EndPtr;
469 }
470 }
471 }
472 }
473 }
474
475 Variable = GetNextVariablePtr (Variable);
476 }
477 //
478 // While (...)
479 //
480 }
481 //
482 // for (...)
483 //
484
485 //
486 // if VAR_IN_DELETED_TRANSITION found, and VAR_ADDED not found,
487 // we return it.
488 //
489 if (InDeleteVariable != NULL) {
490 PtrTrack->CurrPtr = InDeleteVariable;
491 PtrTrack->Type = (VARIABLE_STORAGE_TYPE) InDeleteIndex;
492 PtrTrack->StartPtr = InDeleteStartPtr;
493 PtrTrack->EndPtr = InDeleteEndPtr;
494 return EFI_SUCCESS;
495 }
496
497 PtrTrack->CurrPtr = NULL;
498 return EFI_NOT_FOUND;
499 }
500
501 EFI_STATUS
502 EFIAPI
503 GetVariable (
504 IN CHAR16 *VariableName,
505 IN EFI_GUID *VendorGuid,
506 OUT UINT32 *Attributes OPTIONAL,
507 IN OUT UINTN *DataSize,
508 OUT VOID *Data
509 )
510 /*++
511
512 Routine Description:
513
514 This code finds variable in storage blocks (Volatile or Non-Volatile)
515
516 Arguments:
517
518 VariableName Name of Variable to be found
519 VendorGuid Variable vendor GUID
520 Attributes OPTIONAL Attribute value of the variable found
521 DataSize Size of Data found. If size is less than the
522 data, this value contains the required size.
523 Data Data pointer
524
525 Returns:
526
527 EFI STATUS
528
529 --*/
530 {
531 VARIABLE_POINTER_TRACK Variable;
532 UINTN VarDataSize;
533 EFI_STATUS Status;
534
535 if (VariableName == NULL || VendorGuid == NULL || DataSize == NULL) {
536 return EFI_INVALID_PARAMETER;
537 }
538
539 //
540 // Find existing variable
541 //
542 Status = FindVariable (VariableName, VendorGuid, &Variable);
543
544 if (Variable.CurrPtr == NULL || EFI_ERROR (Status)) {
545 return Status;
546 }
547 //
548 // Get data size
549 //
550 VarDataSize = Variable.CurrPtr->DataSize;
551 if (*DataSize >= VarDataSize) {
552 if (Data == NULL) {
553 return EFI_INVALID_PARAMETER;
554 }
555 CopyMem (Data, GetVariableDataPtr (Variable.CurrPtr), VarDataSize);
556
557 if (Attributes != NULL) {
558 *Attributes = Variable.CurrPtr->Attributes;
559 }
560
561 *DataSize = VarDataSize;
562
563 return EFI_SUCCESS;
564 } else {
565 *DataSize = VarDataSize;
566 return EFI_BUFFER_TOO_SMALL;
567 }
568 }
569
570 EFI_STATUS
571 EFIAPI
572 GetNextVariableName (
573 IN OUT UINTN *VariableNameSize,
574 IN OUT CHAR16 *VariableName,
575 IN OUT EFI_GUID *VendorGuid
576 )
577 /*++
578
579 Routine Description:
580
581 This code Finds the Next available variable
582
583 Arguments:
584
585 VariableNameSize Size of the variable
586 VariableName Pointer to variable name
587 VendorGuid Variable Vendor Guid
588
589 Returns:
590
591 EFI STATUS
592
593 --*/
594 {
595 VARIABLE_POINTER_TRACK Variable;
596 UINTN VarNameSize;
597 EFI_STATUS Status;
598
599 if (VariableNameSize == NULL || VariableName == NULL || VendorGuid == NULL) {
600 return EFI_INVALID_PARAMETER;
601 }
602
603 Status = FindVariable (VariableName, VendorGuid, &Variable);
604
605 if (Variable.CurrPtr == NULL || EFI_ERROR (Status)) {
606 return Status;
607 }
608
609 if (VariableName[0] != 0) {
610 //
611 // If variable name is not NULL, get next variable
612 //
613 Variable.CurrPtr = GetNextVariablePtr (Variable.CurrPtr);
614 }
615
616 while (TRUE) {
617 //
618 // The order we find variable is: 1). NonVolatile; 2). Volatile
619 // If both volatile and non-volatile variable store are parsed,
620 // return not found
621 //
622 if (Variable.CurrPtr >= Variable.EndPtr || Variable.CurrPtr == NULL) {
623 if (Variable.Type == Volatile) {
624 //
625 // Since we met the end of Volatile storage, we have parsed all the stores.
626 //
627 return EFI_NOT_FOUND;
628 }
629
630 //
631 // End of NonVolatile, continue to parse Volatile
632 //
633 Variable.Type = Volatile;
634 Variable.StartPtr = (VARIABLE_HEADER *) ((VARIABLE_STORE_HEADER *) mGlobal->VariableBase[Volatile] + 1);
635 Variable.EndPtr = (VARIABLE_HEADER *) GetEndPointer ((VARIABLE_STORE_HEADER *) mGlobal->VariableBase[Volatile]);
636
637 Variable.CurrPtr = Variable.StartPtr;
638 if (!IsValidVariableHeader (Variable.CurrPtr)) {
639 continue;
640 }
641 }
642 //
643 // Variable is found
644 //
645 if (IsValidVariableHeader (Variable.CurrPtr) &&
646 ((Variable.CurrPtr->State == VAR_ADDED) ||
647 (Variable.CurrPtr->State == (VAR_ADDED & VAR_IN_DELETED_TRANSITION)))) {
648 if (!EfiAtRuntime () || (Variable.CurrPtr->Attributes & EFI_VARIABLE_RUNTIME_ACCESS)) {
649 VarNameSize = Variable.CurrPtr->NameSize;
650 if (VarNameSize <= *VariableNameSize) {
651 CopyMem (
652 VariableName,
653 GET_VARIABLE_NAME_PTR (Variable.CurrPtr),
654 VarNameSize
655 );
656 CopyMem (
657 VendorGuid,
658 &Variable.CurrPtr->VendorGuid,
659 sizeof (EFI_GUID)
660 );
661 Status = EFI_SUCCESS;
662 } else {
663 Status = EFI_BUFFER_TOO_SMALL;
664 }
665
666 *VariableNameSize = VarNameSize;
667 return Status;
668 }
669 }
670
671 Variable.CurrPtr = GetNextVariablePtr (Variable.CurrPtr);
672 }
673 }
674
675 EFI_STATUS
676 EFIAPI
677 SetVariable (
678 IN CHAR16 *VariableName,
679 IN EFI_GUID *VendorGuid,
680 IN UINT32 Attributes,
681 IN UINTN DataSize,
682 IN VOID *Data
683 )
684 /*++
685
686 Routine Description:
687
688 This code sets variable in storage blocks (Volatile or Non-Volatile)
689
690 Arguments:
691
692 VariableName Name of Variable to be found
693 VendorGuid Variable vendor GUID
694 Attributes Attribute value of the variable found
695 DataSize Size of Data found. If size is less than the
696 data, this value contains the required size.
697 Data Data pointer
698
699 Returns:
700
701 EFI_INVALID_PARAMETER - Invalid parameter
702 EFI_SUCCESS - Set successfully
703 EFI_OUT_OF_RESOURCES - Resource not enough to set variable
704 EFI_NOT_FOUND - Not found
705 EFI_DEVICE_ERROR - Variable can not be saved due to hardware failure
706 EFI_WRITE_PROTECTED - Variable is read-only
707
708 --*/
709 {
710 VARIABLE_POINTER_TRACK Variable;
711 EFI_STATUS Status;
712 VARIABLE_HEADER *NextVariable;
713 UINTN VarNameSize;
714 UINTN VarNameOffset;
715 UINTN VarDataOffset;
716 UINTN VarSize;
717 UINT8 State;
718 BOOLEAN Reclaimed;
719 VARIABLE_STORAGE_TYPE StorageType;
720
721 Reclaimed = FALSE;
722
723 //
724 // Check input parameters
725 //
726
727 if (VariableName == NULL || VariableName[0] == 0 || VendorGuid == NULL) {
728 return EFI_INVALID_PARAMETER;
729 }
730
731 //
732 // Make sure if runtime bit is set, boot service bit is set also
733 //
734 if ((Attributes & (EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS)) == EFI_VARIABLE_RUNTIME_ACCESS) {
735 return EFI_INVALID_PARAMETER;
736 }
737
738 //
739 // The size of the VariableName, including the Unicode Null in bytes plus
740 // the DataSize is limited to maximum size of FixedPcdGet32(PcdMaxHardwareErrorVariableSize)
741 // bytes for HwErrRec, and FixedPcdGet32(PcdMaxVariableSize) bytes for the others.
742 //
743 if ((Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == EFI_VARIABLE_HARDWARE_ERROR_RECORD) {
744 if ((DataSize > FixedPcdGet32(PcdMaxHardwareErrorVariableSize)) ||
745 (sizeof (VARIABLE_HEADER) + StrSize (VariableName) + DataSize > FixedPcdGet32(PcdMaxHardwareErrorVariableSize))) {
746 return EFI_INVALID_PARAMETER;
747 }
748 } else {
749 if ((DataSize > FixedPcdGet32(PcdMaxVariableSize)) ||
750 (sizeof (VARIABLE_HEADER) + StrSize (VariableName) + DataSize > FixedPcdGet32(PcdMaxVariableSize))) {
751 return EFI_INVALID_PARAMETER;
752 }
753 }
754
755 //
756 // Check whether the input variable is already existed
757 //
758
759 Status = FindVariable (VariableName, VendorGuid, &Variable);
760
761 if (Status == EFI_SUCCESS && Variable.CurrPtr != NULL) {
762 //
763 // Update/Delete existing variable
764 //
765
766 if (EfiAtRuntime ()) {
767 //
768 // If EfiAtRuntime and the variable is Volatile and Runtime Access,
769 // the volatile is ReadOnly, and SetVariable should be aborted and
770 // return EFI_WRITE_PROTECTED.
771 //
772 if (Variable.Type == Volatile) {
773 return EFI_WRITE_PROTECTED;
774 }
775 //
776 // Only variable have NV attribute can be updated/deleted in Runtime
777 //
778 if (!(Variable.CurrPtr->Attributes & EFI_VARIABLE_NON_VOLATILE)) {
779 return EFI_INVALID_PARAMETER;
780 }
781 }
782
783 //
784 // Setting a data variable with no access, or zero DataSize attributes
785 // specified causes it to be deleted.
786 //
787 if (DataSize == 0 || (Attributes & (EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS)) == 0) {
788 //
789 // Found this variable in storage
790 //
791 State = Variable.CurrPtr->State;
792 State &= VAR_DELETED;
793
794 Status = mGlobal->VariableStore[Variable.Type]->Write (
795 mGlobal->VariableStore[Variable.Type],
796 VARIABLE_MEMBER_OFFSET (State, (UINTN) Variable.CurrPtr - (UINTN) Variable.StartPtr),
797 sizeof (Variable.CurrPtr->State),
798 &State
799 );
800 //
801 // NOTE: Write operation at least can write data to memory cache
802 // Discard file writing failure here.
803 //
804 return EFI_SUCCESS;
805 }
806
807 //
808 // Found this variable in storage
809 // If the variable is marked valid and the same data has been passed in
810 // then return to the caller immediately.
811 //
812 if ((Variable.CurrPtr->DataSize == DataSize) &&
813 (CompareMem (Data, GetVariableDataPtr (Variable.CurrPtr), DataSize) == 0)
814 ) {
815 return EFI_SUCCESS;
816 } else if ((Variable.CurrPtr->State == VAR_ADDED) ||
817 (Variable.CurrPtr->State == (VAR_ADDED & VAR_IN_DELETED_TRANSITION))) {
818 //
819 // Mark the old variable as in delete transition
820 //
821 State = Variable.CurrPtr->State;
822 State &= VAR_IN_DELETED_TRANSITION;
823
824 Status = mGlobal->VariableStore[Variable.Type]->Write (
825 mGlobal->VariableStore[Variable.Type],
826 VARIABLE_MEMBER_OFFSET (State, (UINTN) Variable.CurrPtr - (UINTN) Variable.StartPtr),
827 sizeof (Variable.CurrPtr->State),
828 &State
829 );
830 //
831 // NOTE: Write operation at least can write data to memory cache
832 // Discard file writing failure here.
833 //
834 }
835 } else if (Status == EFI_NOT_FOUND) {
836 //
837 // Create a new variable
838 //
839
840 //
841 // Make sure we are trying to create a new variable.
842 // Setting a data variable with no access, or zero DataSize attributes means to delete it.
843 //
844 if (DataSize == 0 || (Attributes & (EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS)) == 0) {
845 return EFI_NOT_FOUND;
846 }
847 //
848 // Only variable have NV|RT attribute can be created in Runtime
849 //
850 if (EfiAtRuntime () &&
851 (!(Attributes & EFI_VARIABLE_RUNTIME_ACCESS) || !(Attributes & EFI_VARIABLE_NON_VOLATILE))) {
852 return EFI_INVALID_PARAMETER;
853 }
854
855 } else {
856 //
857 // Status should be EFI_INVALID_PARAMETER here according to return status of FindVariable().
858 //
859 return Status;
860 }
861
862 //
863 // Function part - create a new variable and copy the data.
864 // Both update a variable and create a variable will come here.
865 // We can firstly write all the data in memory, then write them to file
866 // This can reduce the times of write operation
867 //
868
869 NextVariable = (VARIABLE_HEADER *) mGlobal->Scratch;
870
871 NextVariable->StartId = VARIABLE_DATA;
872 NextVariable->Attributes = Attributes;
873 NextVariable->State = VAR_ADDED;
874 NextVariable->Reserved = 0;
875 VarNameOffset = sizeof (VARIABLE_HEADER);
876 VarNameSize = StrSize (VariableName);
877 CopyMem (
878 (UINT8 *) ((UINTN) NextVariable + VarNameOffset),
879 VariableName,
880 VarNameSize
881 );
882 VarDataOffset = VarNameOffset + VarNameSize + GET_PAD_SIZE (VarNameSize);
883 CopyMem (
884 (UINT8 *) ((UINTN) NextVariable + VarDataOffset),
885 Data,
886 DataSize
887 );
888 CopyMem (&NextVariable->VendorGuid, VendorGuid, sizeof (EFI_GUID));
889 //
890 // There will be pad bytes after Data, the NextVariable->NameSize and
891 // NextVariable->DataSize should not include pad size so that variable
892 // service can get actual size in GetVariable
893 //
894 NextVariable->NameSize = (UINT32)VarNameSize;
895 NextVariable->DataSize = (UINT32)DataSize;
896
897 //
898 // The actual size of the variable that stores in storage should
899 // include pad size.
900 // VarDataOffset: offset from begin of current variable header
901 //
902 VarSize = VarDataOffset + DataSize + GET_PAD_SIZE (DataSize);
903
904 StorageType = (Attributes & EFI_VARIABLE_NON_VOLATILE) ? NonVolatile : Volatile;
905
906 if ((UINT32) (VarSize + mGlobal->LastVariableOffset[StorageType]) >
907 ((VARIABLE_STORE_HEADER *) mGlobal->VariableBase[StorageType])->Size
908 ) {
909 if ((StorageType == NonVolatile) && EfiAtRuntime ()) {
910 return EFI_OUT_OF_RESOURCES;
911 }
912 //
913 // Perform garbage collection & reclaim operation
914 //
915 Status = Reclaim (StorageType, Variable.CurrPtr);
916 if (EFI_ERROR (Status)) {
917 //
918 // Reclaim error
919 // we cannot restore to original state, fetal error, report to user
920 //
921 DEBUG ((EFI_D_ERROR, "FSVariable: Recalim error (fetal error) - %r\n", Status));
922 return Status;
923 }
924 //
925 // If still no enough space, return out of resources
926 //
927 if ((UINT32) (VarSize + mGlobal->LastVariableOffset[StorageType]) >
928 ((VARIABLE_STORE_HEADER *) mGlobal->VariableBase[StorageType])->Size
929 ) {
930 return EFI_OUT_OF_RESOURCES;
931 }
932
933 Reclaimed = TRUE;
934 }
935 Status = mGlobal->VariableStore[StorageType]->Write (
936 mGlobal->VariableStore[StorageType],
937 mGlobal->LastVariableOffset[StorageType],
938 VarSize,
939 NextVariable
940 );
941 //
942 // NOTE: Write operation at least can write data to memory cache
943 // Discard file writing failure here.
944 //
945 mGlobal->LastVariableOffset[StorageType] += VarSize;
946
947 //
948 // Mark the old variable as deleted
949 //
950 if (!Reclaimed && !EFI_ERROR (Status) && Variable.CurrPtr != NULL) {
951 State = Variable.CurrPtr->State;
952 State &= VAR_DELETED;
953
954 Status = mGlobal->VariableStore[StorageType]->Write (
955 mGlobal->VariableStore[StorageType],
956 VARIABLE_MEMBER_OFFSET (State, (UINTN) Variable.CurrPtr - (UINTN) Variable.StartPtr),
957 sizeof (Variable.CurrPtr->State),
958 &State
959 );
960 //
961 // NOTE: Write operation at least can write data to memory cache
962 // Discard file writing failure here.
963 //
964 }
965
966 return EFI_SUCCESS;
967 }
968
969 EFI_STATUS
970 EFIAPI
971 QueryVariableInfo (
972 IN UINT32 Attributes,
973 OUT UINT64 *MaximumVariableStorageSize,
974 OUT UINT64 *RemainingVariableStorageSize,
975 OUT UINT64 *MaximumVariableSize
976 )
977 /*++
978
979 Routine Description:
980
981 This code returns information about the EFI variables.
982
983 Arguments:
984
985 Attributes Attributes bitmask to specify the type of variables
986 on which to return information.
987 MaximumVariableStorageSize Pointer to the maximum size of the storage space available
988 for the EFI variables associated with the attributes specified.
989 RemainingVariableStorageSize Pointer to the remaining size of the storage space available
990 for the EFI variables associated with the attributes specified.
991 MaximumVariableSize Pointer to the maximum size of the individual EFI variables
992 associated with the attributes specified.
993
994 Returns:
995
996 EFI STATUS
997 EFI_INVALID_PARAMETER - An invalid combination of attribute bits was supplied.
998 EFI_SUCCESS - Query successfully.
999 EFI_UNSUPPORTED - The attribute is not supported on this platform.
1000
1001 --*/
1002 {
1003 VARIABLE_HEADER *Variable;
1004 VARIABLE_HEADER *NextVariable;
1005 UINT64 VariableSize;
1006 VARIABLE_STORE_HEADER *VariableStoreHeader;
1007
1008 if(MaximumVariableStorageSize == NULL || RemainingVariableStorageSize == NULL || MaximumVariableSize == NULL || Attributes == 0) {
1009 return EFI_INVALID_PARAMETER;
1010 }
1011
1012 if((Attributes & (EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_HARDWARE_ERROR_RECORD)) == 0) {
1013 //
1014 // Make sure the Attributes combination is supported by the platform.
1015 //
1016 return EFI_UNSUPPORTED;
1017 }
1018 else if ((Attributes & (EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS)) == EFI_VARIABLE_RUNTIME_ACCESS) {
1019 //
1020 // Make sure if runtime bit is set, boot service bit is set also.
1021 //
1022 return EFI_INVALID_PARAMETER;
1023 } else if (EfiAtRuntime () && !(Attributes & EFI_VARIABLE_RUNTIME_ACCESS)) {
1024 //
1025 // Make sure RT Attribute is set if we are in Runtime phase.
1026 //
1027 return EFI_INVALID_PARAMETER;
1028 }
1029
1030 VariableStoreHeader = (VARIABLE_STORE_HEADER *) mGlobal->VariableBase[
1031 (Attributes & EFI_VARIABLE_NON_VOLATILE) ? NonVolatile : Volatile
1032 ];
1033 //
1034 // Now let's fill *MaximumVariableStorageSize *RemainingVariableStorageSize
1035 // with the storage size (excluding the storage header size).
1036 //
1037 *MaximumVariableStorageSize = VariableStoreHeader->Size - sizeof (VARIABLE_STORE_HEADER);
1038 *RemainingVariableStorageSize = VariableStoreHeader->Size - sizeof (VARIABLE_STORE_HEADER);
1039
1040 //
1041 // Let *MaximumVariableSize be FixedPcdGet32(PcdMaxVariableSize) with the exception of the variable header size.
1042 //
1043 *MaximumVariableSize = FixedPcdGet32(PcdMaxVariableSize) - sizeof (VARIABLE_HEADER);
1044
1045 //
1046 // Harware error record variable needs larger size.
1047 //
1048 if ((Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == EFI_VARIABLE_HARDWARE_ERROR_RECORD) {
1049 *MaximumVariableSize = FixedPcdGet32(PcdMaxHardwareErrorVariableSize) - sizeof (VARIABLE_HEADER);
1050 }
1051
1052 //
1053 // Point to the starting address of the variables.
1054 //
1055 Variable = (VARIABLE_HEADER *) (VariableStoreHeader + 1);
1056
1057 //
1058 // Now walk through the related variable store.
1059 //
1060 while (IsValidVariableHeader (Variable) && (Variable < GetEndPointer (VariableStoreHeader))) {
1061 NextVariable = GetNextVariablePtr (Variable);
1062 VariableSize = (UINT64) (UINTN) NextVariable - (UINT64) (UINTN) Variable;
1063
1064 if (EfiAtRuntime ()) {
1065 //
1066 // we don't take the state of the variables in mind
1067 // when calculating RemainingVariableStorageSize,
1068 // since the space occupied by variables not marked with
1069 // VAR_ADDED is not allowed to be reclaimed in Runtime.
1070 //
1071 *RemainingVariableStorageSize -= VariableSize;
1072 } else {
1073 //
1074 // Only care about Variables with State VAR_ADDED,because
1075 // the space not marked as VAR_ADDED is reclaimable now.
1076 //
1077 if ((Variable->State == VAR_ADDED) ||
1078 (Variable->State == (VAR_ADDED & VAR_IN_DELETED_TRANSITION))) {
1079 *RemainingVariableStorageSize -= VariableSize;
1080 }
1081 }
1082
1083 //
1084 // Go to the next one
1085 //
1086 Variable = NextVariable;
1087 }
1088
1089 if (*RemainingVariableStorageSize < sizeof (VARIABLE_HEADER)) {
1090 *MaximumVariableSize = 0;
1091 } else if ((*RemainingVariableStorageSize - sizeof (VARIABLE_HEADER)) < *MaximumVariableSize) {
1092 *MaximumVariableSize = *RemainingVariableStorageSize - sizeof (VARIABLE_HEADER);
1093 }
1094
1095 return EFI_SUCCESS;
1096 }
1097
1098 EFI_STATUS
1099 EFIAPI
1100 VariableServiceInitialize (
1101 IN EFI_HANDLE ImageHandle,
1102 IN EFI_SYSTEM_TABLE *SystemTable
1103 )
1104 /*++
1105
1106 Routine Description:
1107 This function does initialization for variable services
1108
1109 Arguments:
1110
1111 ImageHandle - The firmware allocated handle for the EFI image.
1112 SystemTable - A pointer to the EFI System Table.
1113
1114 Returns:
1115
1116 Status code.
1117
1118 EFI_NOT_FOUND - Variable store area not found.
1119 EFI_SUCCESS - Variable services successfully initialized.
1120
1121 --*/
1122 {
1123 EFI_STATUS Status;
1124 EFI_HANDLE NewHandle;
1125 VS_DEV *Dev;
1126 EFI_PEI_HOB_POINTERS GuidHob;
1127 VARIABLE_HEADER *NextVariable;
1128 VARIABLE_STORE_HEADER *VariableStoreHeader;
1129 EFI_FLASH_MAP_FS_ENTRY_DATA *FlashMapEntryData;
1130 EFI_FLASH_SUBAREA_ENTRY VariableStoreEntry;
1131 UINT64 BaseAddress;
1132 UINT64 Length;
1133 EFI_GCD_MEMORY_SPACE_DESCRIPTOR GcdDescriptor;
1134
1135 Status = gBS->AllocatePool (
1136 EfiRuntimeServicesData,
1137 (UINTN) sizeof (VARIABLE_GLOBAL),
1138 (VOID**) &mGlobal
1139 );
1140 if (EFI_ERROR (Status)) {
1141 return Status;
1142 }
1143
1144 GuidHob.Raw = GetHobList ();
1145 FlashMapEntryData = NULL;
1146 while ((GuidHob.Raw = GetNextGuidHob (&gEfiFlashMapHobGuid, GuidHob.Raw)) != NULL) {
1147 FlashMapEntryData = (EFI_FLASH_MAP_FS_ENTRY_DATA *) GET_GUID_HOB_DATA (GuidHob.Guid);
1148 if (FlashMapEntryData->AreaType == EFI_FLASH_AREA_EFI_VARIABLES) {
1149 break;
1150 }
1151 GuidHob.Raw = GET_NEXT_HOB (GuidHob);
1152 }
1153
1154 if (FlashMapEntryData == NULL) {
1155 DEBUG ((EFI_D_ERROR, "FSVariable: Could not find flash area for variable!\n"));
1156 Status = EFI_NOT_FOUND;
1157 return Status;
1158 }
1159
1160 CopyMem(
1161 (VOID*)&VariableStoreEntry,
1162 (VOID*)&FlashMapEntryData->Entries[0],
1163 sizeof(EFI_FLASH_SUBAREA_ENTRY)
1164 );
1165
1166 //
1167 // Mark the variable storage region of the FLASH as RUNTIME
1168 //
1169 BaseAddress = VariableStoreEntry.Base & (~EFI_PAGE_MASK);
1170 Length = VariableStoreEntry.Length + (VariableStoreEntry.Base - BaseAddress);
1171 Length = (Length + EFI_PAGE_SIZE - 1) & (~EFI_PAGE_MASK);
1172 Status = gDS->GetMemorySpaceDescriptor (BaseAddress, &GcdDescriptor);
1173 if (EFI_ERROR (Status)) {
1174 Status = EFI_UNSUPPORTED;
1175 return Status;
1176 }
1177 Status = gDS->SetMemorySpaceAttributes (
1178 BaseAddress,
1179 Length,
1180 GcdDescriptor.Attributes | EFI_MEMORY_RUNTIME
1181 );
1182 if (EFI_ERROR (Status)) {
1183 Status = EFI_UNSUPPORTED;
1184 return Status;
1185 }
1186
1187 Status = FileStorageConstructor (
1188 &mGlobal->VariableStore[NonVolatile],
1189 &mGlobal->GoVirtualChildEvent[NonVolatile],
1190 VariableStoreEntry.Base,
1191 (UINT32) VariableStoreEntry.Length,
1192 FlashMapEntryData->VolumeId,
1193 FlashMapEntryData->FilePath
1194 );
1195 ASSERT_EFI_ERROR (Status);
1196
1197 //
1198 // Volatile Storage
1199 //
1200 Status = MemStorageConstructor (
1201 &mGlobal->VariableStore[Volatile],
1202 &mGlobal->GoVirtualChildEvent[Volatile],
1203 VOLATILE_VARIABLE_STORE_SIZE
1204 );
1205 ASSERT_EFI_ERROR (Status);
1206
1207 //
1208 // Scratch
1209 //
1210 Status = gBS->AllocatePool (
1211 EfiRuntimeServicesData,
1212 VARIABLE_SCRATCH_SIZE,
1213 &mGlobal->Scratch
1214 );
1215 ASSERT_EFI_ERROR (Status);
1216
1217 //
1218 // 1. NV Storage
1219 //
1220 Dev = DEV_FROM_THIS (mGlobal->VariableStore[NonVolatile]);
1221 VariableStoreHeader = (VARIABLE_STORE_HEADER *) VAR_DATA_PTR (Dev);
1222 if (GetVariableStoreStatus (VariableStoreHeader) == EfiValid) {
1223 if (~VariableStoreHeader->Size == 0) {
1224 VariableStoreHeader->Size = (UINT32) VariableStoreEntry.Length;
1225 }
1226 }
1227 //
1228 // Calculate LastVariableOffset
1229 //
1230 NextVariable = (VARIABLE_HEADER *) (VariableStoreHeader + 1);
1231 while (IsValidVariableHeader (NextVariable)) {
1232 NextVariable = GetNextVariablePtr (NextVariable);
1233 }
1234 mGlobal->LastVariableOffset[NonVolatile] = (UINTN) NextVariable - (UINTN) VariableStoreHeader;
1235 mGlobal->VariableBase[NonVolatile] = VariableStoreHeader;
1236
1237 //
1238 // Reclaim if remaining space is too small
1239 //
1240 if ((VariableStoreHeader->Size - mGlobal->LastVariableOffset[NonVolatile]) < VARIABLE_RECLAIM_THRESHOLD) {
1241 Status = Reclaim (NonVolatile, NULL);
1242 if (EFI_ERROR (Status)) {
1243 //
1244 // Reclaim error
1245 // we cannot restore to original state
1246 //
1247 DEBUG ((EFI_D_ERROR, "FSVariable: Recalim error (fetal error) - %r\n", Status));
1248 ASSERT_EFI_ERROR (Status);
1249 }
1250 }
1251
1252 //
1253 // 2. Volatile Storage
1254 //
1255 Dev = DEV_FROM_THIS (mGlobal->VariableStore[Volatile]);
1256 VariableStoreHeader = (VARIABLE_STORE_HEADER *) VAR_DATA_PTR (Dev);
1257 mGlobal->VariableBase[Volatile] = VAR_DATA_PTR (Dev);
1258 mGlobal->LastVariableOffset[Volatile] = sizeof (VARIABLE_STORE_HEADER);
1259 //
1260 // init store_header & body in memory.
1261 //
1262 mGlobal->VariableStore[Volatile]->Erase (mGlobal->VariableStore[Volatile]);
1263 mGlobal->VariableStore[Volatile]->Write (
1264 mGlobal->VariableStore[Volatile],
1265 0,
1266 sizeof (VARIABLE_STORE_HEADER),
1267 &mStoreHeaderTemplate
1268 );
1269
1270
1271 SystemTable->RuntimeServices->GetVariable = GetVariable;
1272 SystemTable->RuntimeServices->GetNextVariableName = GetNextVariableName;
1273 SystemTable->RuntimeServices->SetVariable = SetVariable;
1274
1275 SystemTable->RuntimeServices->QueryVariableInfo = QueryVariableInfo;
1276
1277 //
1278 // Now install the Variable Runtime Architectural Protocol on a new handle
1279 //
1280 NewHandle = NULL;
1281 Status = gBS->InstallMultipleProtocolInterfaces (
1282 &NewHandle,
1283 &gEfiVariableArchProtocolGuid,
1284 NULL,
1285 &gEfiVariableWriteArchProtocolGuid,
1286 NULL,
1287 NULL
1288 );
1289 ASSERT_EFI_ERROR (Status);
1290
1291 return Status;
1292
1293 //Shutdown:
1294 // EfiShutdownRuntimeDriverLib ();
1295 // return Status;
1296 }
1297
1298
1299
1300 VOID
1301 EFIAPI
1302 OnVirtualAddressChangeFsv (
1303 IN EFI_EVENT Event,
1304 IN VOID *Context
1305 )
1306 {
1307 UINTN Index;
1308
1309 for (Index = 0; Index < MaxType; Index++) {
1310 mGlobal->GoVirtualChildEvent[Index] (Event, mGlobal->VariableStore[Index]);
1311 EfiConvertPointer (0, (VOID**) &mGlobal->VariableStore[Index]);
1312 EfiConvertPointer (0, &mGlobal->VariableBase[Index]);
1313 }
1314 EfiConvertPointer (0, &mGlobal->Scratch);
1315 EfiConvertPointer (0, (VOID**) &mGlobal);
1316 }