]> git.proxmox.com Git - mirror_edk2.git/blob - DuetPkg/FSVariable/FSVariable.c
Add missing module for duet package.
[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 #if (EFI_SPECIFICATION_VERSION >= 0x0002000A)
747 //
748 // The size of the VariableName, including the Unicode Null in bytes plus
749 // the DataSize is limited to maximum size of MAX_HARDWARE_ERROR_VARIABLE_SIZE (32K)
750 // bytes for HwErrRec, and MAX_VARIABLE_SIZE (1024) bytes for the others.
751 //
752 if ((Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == EFI_VARIABLE_HARDWARE_ERROR_RECORD) {
753 if ((DataSize > MAX_HARDWARE_ERROR_VARIABLE_SIZE) ||
754 (sizeof (VARIABLE_HEADER) + StrSize (VariableName) + DataSize > MAX_HARDWARE_ERROR_VARIABLE_SIZE)) {
755 return EFI_INVALID_PARAMETER;
756 }
757 } else {
758 if ((DataSize > MAX_VARIABLE_SIZE) ||
759 (sizeof (VARIABLE_HEADER) + StrSize (VariableName) + DataSize > MAX_VARIABLE_SIZE)) {
760 return EFI_INVALID_PARAMETER;
761 }
762 }
763 #else
764 //
765 // The size of the VariableName, including the Unicode Null in bytes plus
766 // the DataSize is limited to maximum size of MAX_VARIABLE_SIZE (1024) bytes.
767 //
768 if ((DataSize > MAX_VARIABLE_SIZE) ||
769 (sizeof (VARIABLE_HEADER) + StrSize (VariableName) + DataSize > MAX_VARIABLE_SIZE)) {
770 return EFI_INVALID_PARAMETER;
771 }
772 #endif
773 //
774 // Check whether the input variable is already existed
775 //
776
777 Status = FindVariable (VariableName, VendorGuid, &Variable);
778
779 if (Status == EFI_SUCCESS && Variable.CurrPtr != NULL) {
780 //
781 // Update/Delete existing variable
782 //
783
784 if (EfiAtRuntime ()) {
785 //
786 // If EfiAtRuntime and the variable is Volatile and Runtime Access,
787 // the volatile is ReadOnly, and SetVariable should be aborted and
788 // return EFI_WRITE_PROTECTED.
789 //
790 if (Variable.Type == Volatile) {
791 return EFI_WRITE_PROTECTED;
792 }
793 //
794 // Only variable have NV attribute can be updated/deleted in Runtime
795 //
796 if (!(Variable.CurrPtr->Attributes & EFI_VARIABLE_NON_VOLATILE)) {
797 return EFI_INVALID_PARAMETER;
798 }
799 }
800
801 //
802 // Setting a data variable with no access, or zero DataSize attributes
803 // specified causes it to be deleted.
804 //
805 if (DataSize == 0 || (Attributes & (EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS)) == 0) {
806 //
807 // Found this variable in storage
808 //
809 State = Variable.CurrPtr->State;
810 State &= VAR_DELETED;
811
812 Status = mGlobal->VariableStore[Variable.Type]->Write (
813 mGlobal->VariableStore[Variable.Type],
814 VARIABLE_MEMBER_OFFSET (State, (UINTN) Variable.CurrPtr - (UINTN) Variable.StartPtr),
815 sizeof (Variable.CurrPtr->State),
816 &State
817 );
818 //
819 // NOTE: Write operation at least can write data to memory cache
820 // Discard file writing failure here.
821 //
822 return EFI_SUCCESS;
823 }
824
825 //
826 // Found this variable in storage
827 // If the variable is marked valid and the same data has been passed in
828 // then return to the caller immediately.
829 //
830 if ((Variable.CurrPtr->DataSize == DataSize) &&
831 (CompareMem (Data, GetVariableDataPtr (Variable.CurrPtr), DataSize) == 0)
832 ) {
833 return EFI_SUCCESS;
834 } else if ((Variable.CurrPtr->State == VAR_ADDED) ||
835 (Variable.CurrPtr->State == (VAR_ADDED & VAR_IN_DELETED_TRANSITION))) {
836 //
837 // Mark the old variable as in delete transition
838 //
839 State = Variable.CurrPtr->State;
840 State &= VAR_IN_DELETED_TRANSITION;
841
842 Status = mGlobal->VariableStore[Variable.Type]->Write (
843 mGlobal->VariableStore[Variable.Type],
844 VARIABLE_MEMBER_OFFSET (State, (UINTN) Variable.CurrPtr - (UINTN) Variable.StartPtr),
845 sizeof (Variable.CurrPtr->State),
846 &State
847 );
848 //
849 // NOTE: Write operation at least can write data to memory cache
850 // Discard file writing failure here.
851 //
852 }
853 } else if (Status == EFI_NOT_FOUND) {
854 //
855 // Create a new variable
856 //
857
858 //
859 // Make sure we are trying to create a new variable.
860 // Setting a data variable with no access, or zero DataSize attributes means to delete it.
861 //
862 if (DataSize == 0 || (Attributes & (EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS)) == 0) {
863 return EFI_NOT_FOUND;
864 }
865 //
866 // Only variable have NV|RT attribute can be created in Runtime
867 //
868 if (EfiAtRuntime () &&
869 (!(Attributes & EFI_VARIABLE_RUNTIME_ACCESS) || !(Attributes & EFI_VARIABLE_NON_VOLATILE))) {
870 return EFI_INVALID_PARAMETER;
871 }
872
873 } else {
874 //
875 // Status should be EFI_INVALID_PARAMETER here according to return status of FindVariable().
876 //
877 return Status;
878 }
879
880 //
881 // Function part - create a new variable and copy the data.
882 // Both update a variable and create a variable will come here.
883 // We can firstly write all the data in memory, then write them to file
884 // This can reduce the times of write operation
885 //
886
887 NextVariable = (VARIABLE_HEADER *) mGlobal->Scratch;
888
889 NextVariable->StartId = VARIABLE_DATA;
890 NextVariable->Attributes = Attributes;
891 NextVariable->State = VAR_ADDED;
892 NextVariable->Reserved = 0;
893 VarNameOffset = sizeof (VARIABLE_HEADER);
894 VarNameSize = StrSize (VariableName);
895 CopyMem (
896 (UINT8 *) ((UINTN) NextVariable + VarNameOffset),
897 VariableName,
898 VarNameSize
899 );
900 VarDataOffset = VarNameOffset + VarNameSize + GET_PAD_SIZE (VarNameSize);
901 CopyMem (
902 (UINT8 *) ((UINTN) NextVariable + VarDataOffset),
903 Data,
904 DataSize
905 );
906 CopyMem (&NextVariable->VendorGuid, VendorGuid, sizeof (EFI_GUID));
907 //
908 // There will be pad bytes after Data, the NextVariable->NameSize and
909 // NextVariable->DataSize should not include pad size so that variable
910 // service can get actual size in GetVariable
911 //
912 NextVariable->NameSize = (UINT32)VarNameSize;
913 NextVariable->DataSize = (UINT32)DataSize;
914
915 //
916 // The actual size of the variable that stores in storage should
917 // include pad size.
918 // VarDataOffset: offset from begin of current variable header
919 //
920 VarSize = VarDataOffset + DataSize + GET_PAD_SIZE (DataSize);
921
922 StorageType = (Attributes & EFI_VARIABLE_NON_VOLATILE) ? NonVolatile : Volatile;
923
924 if ((UINT32) (VarSize + mGlobal->LastVariableOffset[StorageType]) >
925 ((VARIABLE_STORE_HEADER *) mGlobal->VariableBase[StorageType])->Size
926 ) {
927 if ((StorageType == NonVolatile) && EfiAtRuntime ()) {
928 return EFI_OUT_OF_RESOURCES;
929 }
930 //
931 // Perform garbage collection & reclaim operation
932 //
933 Status = Reclaim (StorageType, Variable.CurrPtr);
934 if (EFI_ERROR (Status)) {
935 //
936 // Reclaim error
937 // we cannot restore to original state, fetal error, report to user
938 //
939 DEBUG ((EFI_D_ERROR, "FSVariable: Recalim error (fetal error) - %r\n", Status));
940 return Status;
941 }
942 //
943 // If still no enough space, return out of resources
944 //
945 if ((UINT32) (VarSize + mGlobal->LastVariableOffset[StorageType]) >
946 ((VARIABLE_STORE_HEADER *) mGlobal->VariableBase[StorageType])->Size
947 ) {
948 return EFI_OUT_OF_RESOURCES;
949 }
950
951 Reclaimed = TRUE;
952 }
953 Status = mGlobal->VariableStore[StorageType]->Write (
954 mGlobal->VariableStore[StorageType],
955 mGlobal->LastVariableOffset[StorageType],
956 VarSize,
957 NextVariable
958 );
959 //
960 // NOTE: Write operation at least can write data to memory cache
961 // Discard file writing failure here.
962 //
963 mGlobal->LastVariableOffset[StorageType] += VarSize;
964
965 //
966 // Mark the old variable as deleted
967 //
968 if (!Reclaimed && !EFI_ERROR (Status) && Variable.CurrPtr != NULL) {
969 State = Variable.CurrPtr->State;
970 State &= VAR_DELETED;
971
972 Status = mGlobal->VariableStore[StorageType]->Write (
973 mGlobal->VariableStore[StorageType],
974 VARIABLE_MEMBER_OFFSET (State, (UINTN) Variable.CurrPtr - (UINTN) Variable.StartPtr),
975 sizeof (Variable.CurrPtr->State),
976 &State
977 );
978 //
979 // NOTE: Write operation at least can write data to memory cache
980 // Discard file writing failure here.
981 //
982 }
983
984 return EFI_SUCCESS;
985 }
986
987 #if (EFI_SPECIFICATION_VERSION >= 0x00020000)
988 EFI_STATUS
989 EFIAPI
990 QueryVariableInfo (
991 IN UINT32 Attributes,
992 OUT UINT64 *MaximumVariableStorageSize,
993 OUT UINT64 *RemainingVariableStorageSize,
994 OUT UINT64 *MaximumVariableSize
995 )
996 /*++
997
998 Routine Description:
999
1000 This code returns information about the EFI variables.
1001
1002 Arguments:
1003
1004 Attributes Attributes bitmask to specify the type of variables
1005 on which to return information.
1006 MaximumVariableStorageSize Pointer to the maximum size of the storage space available
1007 for the EFI variables associated with the attributes specified.
1008 RemainingVariableStorageSize Pointer to the remaining size of the storage space available
1009 for the EFI variables associated with the attributes specified.
1010 MaximumVariableSize Pointer to the maximum size of the individual EFI variables
1011 associated with the attributes specified.
1012
1013 Returns:
1014
1015 EFI STATUS
1016 EFI_INVALID_PARAMETER - An invalid combination of attribute bits was supplied.
1017 EFI_SUCCESS - Query successfully.
1018 EFI_UNSUPPORTED - The attribute is not supported on this platform.
1019
1020 --*/
1021 {
1022 VARIABLE_HEADER *Variable;
1023 VARIABLE_HEADER *NextVariable;
1024 UINT64 VariableSize;
1025 VARIABLE_STORE_HEADER *VariableStoreHeader;
1026
1027 if(MaximumVariableStorageSize == NULL || RemainingVariableStorageSize == NULL || MaximumVariableSize == NULL || Attributes == 0) {
1028 return EFI_INVALID_PARAMETER;
1029 }
1030
1031 #if (EFI_SPECIFICATION_VERSION >= 0x0002000A)
1032 if((Attributes & (EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_HARDWARE_ERROR_RECORD)) == 0) {
1033 //
1034 // Make sure the Attributes combination is supported by the platform.
1035 //
1036 return EFI_UNSUPPORTED;
1037 }
1038 #else
1039 if((Attributes & (EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS)) == 0) {
1040 //
1041 // Make sure the Attributes combination is supported by the platform.
1042 //
1043 return EFI_UNSUPPORTED;
1044 }
1045 #endif
1046 else if ((Attributes & (EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS)) == EFI_VARIABLE_RUNTIME_ACCESS) {
1047 //
1048 // Make sure if runtime bit is set, boot service bit is set also.
1049 //
1050 return EFI_INVALID_PARAMETER;
1051 } else if (EfiAtRuntime () && !(Attributes & EFI_VARIABLE_RUNTIME_ACCESS)) {
1052 //
1053 // Make sure RT Attribute is set if we are in Runtime phase.
1054 //
1055 return EFI_INVALID_PARAMETER;
1056 }
1057
1058 VariableStoreHeader = (VARIABLE_STORE_HEADER *) mGlobal->VariableBase[
1059 (Attributes & EFI_VARIABLE_NON_VOLATILE) ? NonVolatile : Volatile
1060 ];
1061 //
1062 // Now let's fill *MaximumVariableStorageSize *RemainingVariableStorageSize
1063 // with the storage size (excluding the storage header size).
1064 //
1065 *MaximumVariableStorageSize = VariableStoreHeader->Size - sizeof (VARIABLE_STORE_HEADER);
1066 *RemainingVariableStorageSize = VariableStoreHeader->Size - sizeof (VARIABLE_STORE_HEADER);
1067
1068 //
1069 // Let *MaximumVariableSize be MAX_VARIABLE_SIZE with the exception of the variable header size.
1070 //
1071 *MaximumVariableSize = MAX_VARIABLE_SIZE - sizeof (VARIABLE_HEADER);
1072
1073 #if (EFI_SPECIFICATION_VERSION >= 0x0002000A)
1074 //
1075 // Harware error record variable needs larger size.
1076 //
1077 if ((Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == EFI_VARIABLE_HARDWARE_ERROR_RECORD) {
1078 *MaximumVariableSize = MAX_HARDWARE_ERROR_VARIABLE_SIZE - sizeof (VARIABLE_HEADER);
1079 }
1080 #endif
1081
1082 //
1083 // Point to the starting address of the variables.
1084 //
1085 Variable = (VARIABLE_HEADER *) (VariableStoreHeader + 1);
1086
1087 //
1088 // Now walk through the related variable store.
1089 //
1090 while (IsValidVariableHeader (Variable) && (Variable < GetEndPointer (VariableStoreHeader))) {
1091 NextVariable = GetNextVariablePtr (Variable);
1092 VariableSize = (UINT64) (UINTN) NextVariable - (UINT64) (UINTN) Variable;
1093
1094 if (EfiAtRuntime ()) {
1095 //
1096 // we don't take the state of the variables in mind
1097 // when calculating RemainingVariableStorageSize,
1098 // since the space occupied by variables not marked with
1099 // VAR_ADDED is not allowed to be reclaimed in Runtime.
1100 //
1101 *RemainingVariableStorageSize -= VariableSize;
1102 } else {
1103 //
1104 // Only care about Variables with State VAR_ADDED,because
1105 // the space not marked as VAR_ADDED is reclaimable now.
1106 //
1107 if ((Variable->State == VAR_ADDED) ||
1108 (Variable->State == (VAR_ADDED & VAR_IN_DELETED_TRANSITION))) {
1109 *RemainingVariableStorageSize -= VariableSize;
1110 }
1111 }
1112
1113 //
1114 // Go to the next one
1115 //
1116 Variable = NextVariable;
1117 }
1118
1119 if (*RemainingVariableStorageSize < sizeof (VARIABLE_HEADER)) {
1120 *MaximumVariableSize = 0;
1121 } else if ((*RemainingVariableStorageSize - sizeof (VARIABLE_HEADER)) < *MaximumVariableSize) {
1122 *MaximumVariableSize = *RemainingVariableStorageSize - sizeof (VARIABLE_HEADER);
1123 }
1124
1125 return EFI_SUCCESS;
1126 }
1127 #endif
1128
1129 EFI_STATUS
1130 EFIAPI
1131 VariableServiceInitialize (
1132 IN EFI_HANDLE ImageHandle,
1133 IN EFI_SYSTEM_TABLE *SystemTable
1134 )
1135 /*++
1136
1137 Routine Description:
1138 This function does initialization for variable services
1139
1140 Arguments:
1141
1142 ImageHandle - The firmware allocated handle for the EFI image.
1143 SystemTable - A pointer to the EFI System Table.
1144
1145 Returns:
1146
1147 Status code.
1148
1149 EFI_NOT_FOUND - Variable store area not found.
1150 EFI_SUCCESS - Variable services successfully initialized.
1151
1152 --*/
1153 {
1154 EFI_STATUS Status;
1155 EFI_HANDLE NewHandle;
1156 VS_DEV *Dev;
1157 VOID *HobList;
1158 VARIABLE_HEADER *NextVariable;
1159 VARIABLE_STORE_HEADER *VariableStoreHeader;
1160 EFI_FLASH_MAP_FS_ENTRY_DATA *FlashMapEntryData;
1161 EFI_FLASH_SUBAREA_ENTRY VariableStoreEntry;
1162 VOID *Buffer;
1163 UINT64 BaseAddress;
1164 UINT64 Length;
1165 EFI_GCD_MEMORY_SPACE_DESCRIPTOR GcdDescriptor;
1166
1167 Status = gBS->AllocatePool (
1168 EfiRuntimeServicesData,
1169 (UINTN) sizeof (VARIABLE_GLOBAL),
1170 &mGlobal
1171 );
1172 if (EFI_ERROR (Status)) {
1173 return Status;
1174 }
1175
1176 Status = EfiGetSystemConfigurationTable (&gEfiHobListGuid, &HobList);
1177
1178 if (EFI_ERROR (Status)) {
1179 return Status;
1180 }
1181
1182
1183 for (FlashMapEntryData = NULL; ;) {
1184 Buffer = GetNextGuidHob (&gEfiFlashMapHobGuid, &HobList);
1185
1186 FlashMapEntryData = (EFI_FLASH_MAP_FS_ENTRY_DATA *) Buffer;
1187
1188 //
1189 // Get the variable store area
1190 //
1191 if (FlashMapEntryData->AreaType == EFI_FLASH_AREA_EFI_VARIABLES) {
1192 break;
1193 }
1194 }
1195
1196 if (EFI_ERROR (Status) || FlashMapEntryData == NULL) {
1197 Status = EFI_NOT_FOUND;
1198 return Status;
1199 }
1200
1201 VariableStoreEntry = FlashMapEntryData->Entries[0];
1202
1203 //
1204 // Mark the variable storage region of the FLASH as RUNTIME
1205 //
1206 BaseAddress = VariableStoreEntry.Base & (~EFI_PAGE_MASK);
1207 Length = VariableStoreEntry.Length + (VariableStoreEntry.Base - BaseAddress);
1208 Length = (Length + EFI_PAGE_SIZE - 1) & (~EFI_PAGE_MASK);
1209 Status = gDS->GetMemorySpaceDescriptor (BaseAddress, &GcdDescriptor);
1210 if (EFI_ERROR (Status)) {
1211 Status = EFI_UNSUPPORTED;
1212 return Status;
1213 }
1214 Status = gDS->SetMemorySpaceAttributes (
1215 BaseAddress,
1216 Length,
1217 GcdDescriptor.Attributes | EFI_MEMORY_RUNTIME
1218 );
1219 if (EFI_ERROR (Status)) {
1220 Status = EFI_UNSUPPORTED;
1221 return Status;
1222 }
1223
1224 Status = FileStorageConstructor (
1225 &mGlobal->VariableStore[NonVolatile],
1226 &mGlobal->GoVirtualChildEvent[NonVolatile],
1227 VariableStoreEntry.Base,
1228 (UINT32) VariableStoreEntry.Length,
1229 FlashMapEntryData->VolumeId,
1230 FlashMapEntryData->FilePath
1231 );
1232 ASSERT_EFI_ERROR (Status);
1233
1234 //
1235 // Volatile Storage
1236 //
1237 Status = MemStorageConstructor (
1238 &mGlobal->VariableStore[Volatile],
1239 &mGlobal->GoVirtualChildEvent[Volatile],
1240 VOLATILE_VARIABLE_STORE_SIZE
1241 );
1242 ASSERT_EFI_ERROR (Status);
1243
1244 //
1245 // Scratch
1246 //
1247 Status = gBS->AllocatePool (
1248 EfiRuntimeServicesData,
1249 VARIABLE_SCRATCH_SIZE,
1250 &mGlobal->Scratch
1251 );
1252 ASSERT_EFI_ERROR (Status);
1253
1254 //
1255 // 1. NV Storage
1256 //
1257 Dev = DEV_FROM_THIS (mGlobal->VariableStore[NonVolatile]);
1258 VariableStoreHeader = (VARIABLE_STORE_HEADER *) VAR_DATA_PTR (Dev);
1259 if (GetVariableStoreStatus (VariableStoreHeader) == EfiValid) {
1260 if (~VariableStoreHeader->Size == 0) {
1261 VariableStoreHeader->Size = (UINT32) VariableStoreEntry.Length;
1262 }
1263 }
1264 //
1265 // Calculate LastVariableOffset
1266 //
1267 NextVariable = (VARIABLE_HEADER *) (VariableStoreHeader + 1);
1268 while (IsValidVariableHeader (NextVariable)) {
1269 NextVariable = GetNextVariablePtr (NextVariable);
1270 }
1271 mGlobal->LastVariableOffset[NonVolatile] = (UINTN) NextVariable - (UINTN) VariableStoreHeader;
1272 mGlobal->VariableBase[NonVolatile] = VariableStoreHeader;
1273
1274 //
1275 // Reclaim if remaining space is too small
1276 //
1277 if ((VariableStoreHeader->Size - mGlobal->LastVariableOffset[NonVolatile]) < VARIABLE_RECLAIM_THRESHOLD) {
1278 Status = Reclaim (NonVolatile, NULL);
1279 if (EFI_ERROR (Status)) {
1280 //
1281 // Reclaim error
1282 // we cannot restore to original state
1283 //
1284 DEBUG ((EFI_D_ERROR, "FSVariable: Recalim error (fetal error) - %r\n", Status));
1285 ASSERT_EFI_ERROR (Status);
1286 }
1287 }
1288
1289 //
1290 // 2. Volatile Storage
1291 //
1292 Dev = DEV_FROM_THIS (mGlobal->VariableStore[Volatile]);
1293 VariableStoreHeader = (VARIABLE_STORE_HEADER *) VAR_DATA_PTR (Dev);
1294 mGlobal->VariableBase[Volatile] = VAR_DATA_PTR (Dev);
1295 mGlobal->LastVariableOffset[Volatile] = sizeof (VARIABLE_STORE_HEADER);
1296 //
1297 // init store_header & body in memory.
1298 //
1299 mGlobal->VariableStore[Volatile]->Erase (mGlobal->VariableStore[Volatile]);
1300 mGlobal->VariableStore[Volatile]->Write (
1301 mGlobal->VariableStore[Volatile],
1302 0,
1303 sizeof (VARIABLE_STORE_HEADER),
1304 &mStoreHeaderTemplate
1305 );
1306
1307
1308 SystemTable->RuntimeServices->GetVariable = GetVariable;
1309 SystemTable->RuntimeServices->GetNextVariableName = GetNextVariableName;
1310 SystemTable->RuntimeServices->SetVariable = SetVariable;
1311
1312 #if (EFI_SPECIFICATION_VERSION >= 0x00020000)
1313 SystemTable->RuntimeServices->QueryVariableInfo = QueryVariableInfo;
1314 #endif
1315
1316 //
1317 // Now install the Variable Runtime Architectural Protocol on a new handle
1318 //
1319 NewHandle = NULL;
1320 Status = gBS->InstallMultipleProtocolInterfaces (
1321 &NewHandle,
1322 &gEfiVariableArchProtocolGuid,
1323 NULL,
1324 &gEfiVariableWriteArchProtocolGuid,
1325 NULL,
1326 NULL
1327 );
1328 ASSERT_EFI_ERROR (Status);
1329
1330 return Status;
1331
1332 //Shutdown:
1333 // EfiShutdownRuntimeDriverLib ();
1334 // return Status;
1335 }
1336
1337
1338
1339 STATIC
1340 VOID
1341 EFIAPI
1342 OnVirtualAddressChange (
1343 IN EFI_EVENT Event,
1344 IN VOID *Context
1345 )
1346 {
1347 UINTN Index;
1348
1349 for (Index = 0; Index < MaxType; Index++) {
1350 mGlobal->GoVirtualChildEvent[Index] (Event, mGlobal->VariableStore[Index]);
1351 EfiConvertPointer (0, &mGlobal->VariableStore[Index]);
1352 EfiConvertPointer (0, &mGlobal->VariableBase[Index]);
1353 }
1354 EfiConvertPointer (0, &mGlobal->Scratch);
1355 EfiConvertPointer (0, &mGlobal);
1356 }