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