1 /*++
2 
3 Caution: This file is used for Duet platform only, do not use them in real platform.
4 All variable code, variable metadata, and variable data used by Duet platform are on
5 disk. They can be changed by user. BIOS is not able to protoect those.
6 Duet trusts all meta data from disk. If variable code, variable metadata and variable
7 data is modified in inproper way, the behavior is undefined.
8 
9 Copyright (c) 2006 - 2016, Intel Corporation. All rights reserved.<BR>
10 This program and the accompanying materials
11 are licensed and made available under the terms and conditions of the BSD License
12 which accompanies this distribution.  The full text of the license may be found at
13 http://opensource.org/licenses/bsd-license.php
14 
15 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
16 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
17 
18 Module Name:
19 
20   FSVariable.c
21 
22 Abstract:
23 
24   Provide support functions for variable services.
25 
26 --*/
27 
28 #include "FSVariable.h"
29 
30 VARIABLE_STORE_HEADER mStoreHeaderTemplate = {
31   VARIABLE_STORE_SIGNATURE,
32   VOLATILE_VARIABLE_STORE_SIZE,
33   VARIABLE_STORE_FORMATTED,
34   VARIABLE_STORE_HEALTHY,
35   0,
36   0
37 };
38 
39 //
40 // Don't use module globals after the SetVirtualAddress map is signaled
41 //
42 VARIABLE_GLOBAL  *mGlobal;
43 
44 /**
45   Update the variable region with Variable information. These are the same
46   arguments as the EFI Variable services.
47 
48   @param[in] VariableName       Name of variable
49 
50   @param[in] VendorGuid         Guid of variable
51 
52   @param[in] Data               Variable data
53 
54   @param[in] DataSize           Size of data. 0 means delete
55 
56   @param[in] Attributes         Attribues of the variable
57 
58   @param[in] Variable           The variable information which is used to keep track of variable usage.
59 
60   @retval EFI_SUCCESS           The update operation is success.
61 
62   @retval EFI_OUT_OF_RESOURCES  Variable region is full, can not write other data into this region.
63 
64 **/
65 EFI_STATUS
66 EFIAPI
67 UpdateVariable (
68   IN      CHAR16                 *VariableName,
69   IN      EFI_GUID               *VendorGuid,
70   IN      VOID                   *Data,
71   IN      UINTN                  DataSize,
72   IN      UINT32                 Attributes OPTIONAL,
73   IN      VARIABLE_POINTER_TRACK *Variable
74   );
75 
76 VOID
77 EFIAPI
78 OnVirtualAddressChangeFsv (
79   IN EFI_EVENT        Event,
80   IN VOID             *Context
81   );
82 
83 VOID
84 EFIAPI
85 OnSimpleFileSystemInstall (
86   IN EFI_EVENT        Event,
87   IN VOID             *Context
88   );
89 
90 BOOLEAN
IsValidVariableHeader(IN VARIABLE_HEADER * Variable)91 IsValidVariableHeader (
92   IN  VARIABLE_HEADER   *Variable
93   )
94 /*++
95 
96 Routine Description:
97 
98   This code checks if variable header is valid or not.
99 
100 Arguments:
101   Variable        Pointer to the Variable Header.
102 
103 Returns:
104   TRUE            Variable header is valid.
105   FALSE           Variable header is not valid.
106 
107 --*/
108 {
109   if (Variable == NULL || Variable->StartId != VARIABLE_DATA) {
110     return FALSE;
111   }
112 
113   return TRUE;
114 }
115 
116 VARIABLE_STORE_STATUS
GetVariableStoreStatus(IN VARIABLE_STORE_HEADER * VarStoreHeader)117 GetVariableStoreStatus (
118   IN VARIABLE_STORE_HEADER *VarStoreHeader
119   )
120 /*++
121 
122 Routine Description:
123 
124   This code gets the current status of Variable Store.
125 
126 Arguments:
127 
128   VarStoreHeader  Pointer to the Variable Store Header.
129 
130 Returns:
131 
132   EfiRaw        Variable store status is raw
133   EfiValid      Variable store status is valid
134   EfiInvalid    Variable store status is invalid
135 
136 --*/
137 {
138   if (CompareGuid (&VarStoreHeader->Signature, &mStoreHeaderTemplate.Signature) &&
139       (VarStoreHeader->Format == mStoreHeaderTemplate.Format) &&
140       (VarStoreHeader->State == mStoreHeaderTemplate.State)
141      ) {
142     return EfiValid;
143   } else if (((UINT32 *)(&VarStoreHeader->Signature))[0] == VAR_DEFAULT_VALUE_32 &&
144              ((UINT32 *)(&VarStoreHeader->Signature))[1] == VAR_DEFAULT_VALUE_32 &&
145              ((UINT32 *)(&VarStoreHeader->Signature))[2] == VAR_DEFAULT_VALUE_32 &&
146              ((UINT32 *)(&VarStoreHeader->Signature))[3] == VAR_DEFAULT_VALUE_32 &&
147              VarStoreHeader->Size == VAR_DEFAULT_VALUE_32 &&
148              VarStoreHeader->Format == VAR_DEFAULT_VALUE &&
149              VarStoreHeader->State == VAR_DEFAULT_VALUE
150           ) {
151 
152     return EfiRaw;
153   } else {
154     return EfiInvalid;
155   }
156 }
157 
158 UINT8 *
GetVariableDataPtr(IN VARIABLE_HEADER * Variable)159 GetVariableDataPtr (
160   IN  VARIABLE_HEADER   *Variable
161   )
162 /*++
163 
164 Routine Description:
165 
166   This code gets the pointer to the variable data.
167 
168 Arguments:
169 
170   Variable            Pointer to the Variable Header.
171 
172 Returns:
173 
174   UINT8*              Pointer to Variable Data
175 
176 --*/
177 {
178   //
179   // Be careful about pad size for alignment
180   //
181   return (UINT8 *) ((UINTN) GET_VARIABLE_NAME_PTR (Variable) + Variable->NameSize + GET_PAD_SIZE (Variable->NameSize));
182 }
183 
184 VARIABLE_HEADER *
GetNextVariablePtr(IN VARIABLE_HEADER * Variable)185 GetNextVariablePtr (
186   IN  VARIABLE_HEADER   *Variable
187   )
188 /*++
189 
190 Routine Description:
191 
192   This code gets the pointer to the next variable header.
193 
194 Arguments:
195 
196   Variable              Pointer to the Variable Header.
197 
198 Returns:
199 
200   VARIABLE_HEADER*      Pointer to next variable header.
201 
202 --*/
203 {
204   if (!IsValidVariableHeader (Variable)) {
205     return NULL;
206   }
207   //
208   // Be careful about pad size for alignment
209   //
210   return (VARIABLE_HEADER *) ((UINTN) GetVariableDataPtr (Variable) + Variable->DataSize + GET_PAD_SIZE (Variable->DataSize));
211 }
212 
213 VARIABLE_HEADER *
GetEndPointer(IN VARIABLE_STORE_HEADER * VarStoreHeader)214 GetEndPointer (
215   IN VARIABLE_STORE_HEADER       *VarStoreHeader
216   )
217 /*++
218 
219 Routine Description:
220 
221   This code gets the pointer to the last variable memory pointer byte
222 
223 Arguments:
224 
225   VarStoreHeader        Pointer to the Variable Store Header.
226 
227 Returns:
228 
229   VARIABLE_HEADER*      Pointer to last unavailable Variable Header
230 
231 --*/
232 {
233   //
234   // The end of variable store
235   //
236   return (VARIABLE_HEADER *) ((UINTN) VarStoreHeader + VarStoreHeader->Size);
237 }
238 
239 BOOLEAN
ExistNewerVariable(IN VARIABLE_HEADER * Variable)240 ExistNewerVariable (
241   IN  VARIABLE_HEADER         *Variable
242   )
243 /*++
244 
245 Routine Description:
246 
247   Check if exist newer variable when doing reclaim
248 
249 Arguments:
250 
251   Variable                    Pointer to start position
252 
253 Returns:
254 
255   TRUE - Exists another variable, which is newer than the current one
256   FALSE  - Doesn't exist another vairable which is newer than the current one
257 
258 --*/
259 {
260   VARIABLE_HEADER       *NextVariable;
261   CHAR16                *VariableName;
262   EFI_GUID              *VendorGuid;
263 
264   VendorGuid   = &Variable->VendorGuid;
265   VariableName = GET_VARIABLE_NAME_PTR(Variable);
266 
267   NextVariable = GetNextVariablePtr (Variable);
268   while (IsValidVariableHeader (NextVariable)) {
269     if ((NextVariable->State == VAR_ADDED) || (NextVariable->State == (VAR_ADDED & VAR_IN_DELETED_TRANSITION))) {
270       //
271       // If match Guid and Name
272       //
273       if (CompareGuid (VendorGuid, &NextVariable->VendorGuid)) {
274          if (CompareMem (VariableName, GET_VARIABLE_NAME_PTR (NextVariable), StrSize (VariableName)) == 0) {
275            return TRUE;
276          }
277        }
278     }
279     NextVariable = GetNextVariablePtr (NextVariable);
280   }
281   return FALSE;
282 }
283 
284 EFI_STATUS
Reclaim(IN VARIABLE_STORAGE_TYPE StorageType,IN VARIABLE_HEADER * CurrentVariable OPTIONAL)285 Reclaim (
286   IN  VARIABLE_STORAGE_TYPE StorageType,
287   IN  VARIABLE_HEADER       *CurrentVariable OPTIONAL
288   )
289 /*++
290 
291 Routine Description:
292 
293   Variable store garbage collection and reclaim operation
294 
295 Arguments:
296 
297   IsVolatile                  The variable store is volatile or not,
298                               if it is non-volatile, need FTW
299   CurrentVairable             If it is not NULL, it means not to process
300                               current variable for Reclaim.
301 
302 Returns:
303 
304   EFI STATUS
305 
306 --*/
307 {
308   VARIABLE_HEADER       *Variable;
309   VARIABLE_HEADER       *NextVariable;
310   VARIABLE_STORE_HEADER *VariableStoreHeader;
311   UINT8                 *ValidBuffer;
312   UINTN                 ValidBufferSize;
313   UINTN                 VariableSize;
314   UINT8                 *CurrPtr;
315   EFI_STATUS            Status;
316 
317   VariableStoreHeader = (VARIABLE_STORE_HEADER *) mGlobal->VariableBase[StorageType];
318 
319   //
320   // Start Pointers for the variable.
321   //
322   Variable        = (VARIABLE_HEADER *) (VariableStoreHeader + 1);
323 
324   //
325   // recaluate the total size of Common/HwErr type variables in non-volatile area.
326   //
327   if (!StorageType) {
328     mGlobal->CommonVariableTotalSize = 0;
329     mGlobal->HwErrVariableTotalSize  = 0;
330   }
331   //
332   // To make the reclaim, here we just allocate a memory that equal to the original memory
333   //
334   ValidBufferSize = sizeof (VARIABLE_STORE_HEADER) + VariableStoreHeader->Size;
335 
336   Status = gBS->AllocatePool (
337                   EfiBootServicesData,
338                   ValidBufferSize,
339                   (VOID**) &ValidBuffer
340                   );
341   if (EFI_ERROR (Status)) {
342     return Status;
343   }
344 
345   CurrPtr = ValidBuffer;
346 
347   //
348   // Copy variable store header
349   //
350   CopyMem (CurrPtr, VariableStoreHeader, sizeof (VARIABLE_STORE_HEADER));
351   CurrPtr += sizeof (VARIABLE_STORE_HEADER);
352 
353   //
354   // Start Pointers for the variable.
355   //
356   Variable = (VARIABLE_HEADER *) (VariableStoreHeader + 1);
357 
358 
359   ValidBufferSize = sizeof (VARIABLE_STORE_HEADER);
360   while (IsValidVariableHeader (Variable)) {
361     NextVariable = GetNextVariablePtr (Variable);
362     //
363     // State VAR_ADDED or VAR_IN_DELETED_TRANSITION are to kept,
364     // The CurrentVariable, is also saved, as SetVariable may fail due to lack of space
365     //
366     if (Variable->State == VAR_ADDED) {
367       VariableSize = (UINTN) NextVariable - (UINTN) Variable;
368       CopyMem (CurrPtr, (UINT8 *) Variable, VariableSize);
369       ValidBufferSize += VariableSize;
370       CurrPtr += VariableSize;
371       if ((!StorageType) && ((Variable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == EFI_VARIABLE_HARDWARE_ERROR_RECORD)) {
372         mGlobal->HwErrVariableTotalSize += VariableSize;
373       } else if ((!StorageType) && ((Variable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) != EFI_VARIABLE_HARDWARE_ERROR_RECORD)) {
374         mGlobal->CommonVariableTotalSize += VariableSize;
375       }
376     } else if (Variable->State == (VAR_ADDED & VAR_IN_DELETED_TRANSITION)) {
377       //
378       // As variables that with the same guid and name may exist in NV due to power failure during SetVariable,
379       // we will only save the latest valid one
380       //
381       if (!ExistNewerVariable(Variable)) {
382         VariableSize = (UINTN) NextVariable - (UINTN) Variable;
383         CopyMem (CurrPtr, (UINT8 *) Variable, VariableSize);
384         //
385         // If CurrentVariable == Variable, mark as VAR_IN_DELETED_TRANSITION
386         //
387         if (Variable != CurrentVariable){
388           ((VARIABLE_HEADER *)CurrPtr)->State = VAR_ADDED;
389         }
390         CurrPtr += VariableSize;
391         ValidBufferSize += VariableSize;
392         if ((!StorageType) && ((Variable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == EFI_VARIABLE_HARDWARE_ERROR_RECORD)) {
393           mGlobal->HwErrVariableTotalSize += VariableSize;
394         } else if ((!StorageType) && ((Variable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) != EFI_VARIABLE_HARDWARE_ERROR_RECORD)) {
395           mGlobal->CommonVariableTotalSize += VariableSize;
396         }
397       }
398     }
399     Variable = NextVariable;
400   }
401 
402   mGlobal->LastVariableOffset[StorageType] = ValidBufferSize;
403 
404   //
405   // TODO: cannot restore to original state, basic FTW needed
406   //
407   Status = mGlobal->VariableStore[StorageType]->Erase (
408                                                   mGlobal->VariableStore[StorageType]
409                                                   );
410   Status = mGlobal->VariableStore[StorageType]->Write (
411                                                     mGlobal->VariableStore[StorageType],
412                                                     0,
413                                                     ValidBufferSize,
414                                                     ValidBuffer
415                                                     );
416 
417   if (EFI_ERROR (Status)) {
418     //
419     // If error, then reset the last variable offset to zero.
420     //
421     mGlobal->LastVariableOffset[StorageType] = 0;
422   };
423 
424   gBS->FreePool (ValidBuffer);
425 
426   return Status;
427 }
428 
429 EFI_STATUS
FindVariable(IN CHAR16 * VariableName,IN EFI_GUID * VendorGuid,OUT VARIABLE_POINTER_TRACK * PtrTrack)430 FindVariable (
431   IN  CHAR16                  *VariableName,
432   IN  EFI_GUID                *VendorGuid,
433   OUT VARIABLE_POINTER_TRACK  *PtrTrack
434   )
435 /*++
436 
437 Routine Description:
438 
439   This code finds variable in storage blocks (Volatile or Non-Volatile)
440 
441 Arguments:
442 
443   VariableName                Name of the variable to be found
444   VendorGuid                  Vendor GUID to be found.
445   PtrTrack                    Variable Track Pointer structure that contains
446                               Variable Information.
447                               Contains the pointer of Variable header.
448 
449 Returns:
450 
451   EFI_INVALID_PARAMETER       - Invalid parameter
452   EFI_SUCCESS                 - Find the specified variable
453   EFI_NOT_FOUND               - Not found
454 
455 --*/
456 {
457   VARIABLE_HEADER         *Variable;
458   VARIABLE_STORE_HEADER   *VariableStoreHeader;
459   UINTN                   Index;
460   VARIABLE_HEADER         *InDeleteVariable;
461   UINTN                   InDeleteIndex;
462   VARIABLE_HEADER         *InDeleteStartPtr;
463   VARIABLE_HEADER         *InDeleteEndPtr;
464 
465   if (VariableName[0] != 0 && VendorGuid == NULL) {
466     return EFI_INVALID_PARAMETER;
467   }
468 
469   InDeleteVariable = NULL;
470   InDeleteIndex    = (UINTN)-1;
471   InDeleteStartPtr = NULL;
472   InDeleteEndPtr   = NULL;
473 
474   for (Index = 0; Index < MaxType; Index ++) {
475     //
476     // 0: Non-Volatile, 1: Volatile
477     //
478     VariableStoreHeader = (VARIABLE_STORE_HEADER *) mGlobal->VariableBase[Index];
479 
480     //
481     // Start Pointers for the variable.
482     // Actual Data Pointer where data can be written.
483     //
484     Variable = (VARIABLE_HEADER *) (VariableStoreHeader + 1);
485 
486     //
487     // Find the variable by walk through non-volatile and volatile variable store
488     //
489     PtrTrack->StartPtr = Variable;
490     PtrTrack->EndPtr   = GetEndPointer (VariableStoreHeader);
491 
492     while ((Variable < PtrTrack->EndPtr) && IsValidVariableHeader (Variable)) {
493       if (Variable->State == VAR_ADDED) {
494         if (!EfiAtRuntime () || (Variable->Attributes & EFI_VARIABLE_RUNTIME_ACCESS)) {
495           if (VariableName[0] == 0) {
496             PtrTrack->CurrPtr = Variable;
497             PtrTrack->Type    = (VARIABLE_STORAGE_TYPE) Index;
498             return EFI_SUCCESS;
499           } else {
500             if (CompareGuid (VendorGuid, &Variable->VendorGuid)) {
501               if (!CompareMem (VariableName, GET_VARIABLE_NAME_PTR (Variable), StrSize (VariableName))) {
502                 PtrTrack->CurrPtr = Variable;
503                 PtrTrack->Type    = (VARIABLE_STORAGE_TYPE) Index;
504                 return EFI_SUCCESS;
505               }
506             }
507           }
508         }
509       } else if (Variable->State == (VAR_ADDED & VAR_IN_DELETED_TRANSITION)) {
510         //
511         // VAR_IN_DELETED_TRANSITION should also be checked.
512         //
513         if (!EfiAtRuntime () || (Variable->Attributes & EFI_VARIABLE_RUNTIME_ACCESS)) {
514           if (VariableName[0] == 0) {
515             InDeleteVariable = Variable;
516             InDeleteIndex    = Index;
517             InDeleteStartPtr = PtrTrack->StartPtr;
518             InDeleteEndPtr   = PtrTrack->EndPtr;
519           } else {
520             if (CompareGuid (VendorGuid, &Variable->VendorGuid)) {
521               if (!CompareMem (VariableName, GET_VARIABLE_NAME_PTR (Variable), StrSize (VariableName))) {
522                 InDeleteVariable = Variable;
523                 InDeleteIndex    = Index;
524                 InDeleteStartPtr = PtrTrack->StartPtr;
525                 InDeleteEndPtr   = PtrTrack->EndPtr;
526               }
527             }
528           }
529         }
530       }
531 
532       Variable = GetNextVariablePtr (Variable);
533     }
534     //
535     // While (...)
536     //
537   }
538   //
539   // for (...)
540   //
541 
542   //
543   // if VAR_IN_DELETED_TRANSITION found, and VAR_ADDED not found,
544   // we return it.
545   //
546   if (InDeleteVariable != NULL) {
547     PtrTrack->CurrPtr  = InDeleteVariable;
548     PtrTrack->Type     = (VARIABLE_STORAGE_TYPE) InDeleteIndex;
549     PtrTrack->StartPtr = InDeleteStartPtr;
550     PtrTrack->EndPtr   = InDeleteEndPtr;
551     return EFI_SUCCESS;
552   }
553 
554   PtrTrack->CurrPtr = NULL;
555   return EFI_NOT_FOUND;
556 }
557 
558 /**
559   Get index from supported language codes according to language string.
560 
561   This code is used to get corresponding index in supported language codes. It can handle
562   RFC4646 and ISO639 language tags.
563   In ISO639 language tags, take 3-characters as a delimitation to find matched string and calculate the index.
564   In RFC4646 language tags, take semicolon as a delimitation to find matched string and calculate the index.
565 
566   For example:
567     SupportedLang  = "engfraengfra"
568     Lang           = "eng"
569     Iso639Language = TRUE
570   The return value is "0".
571   Another example:
572     SupportedLang  = "en;fr;en-US;fr-FR"
573     Lang           = "fr-FR"
574     Iso639Language = FALSE
575   The return value is "3".
576 
577   @param  SupportedLang               Platform supported language codes.
578   @param  Lang                        Configured language.
579   @param  Iso639Language              A bool value to signify if the handler is operated on ISO639 or RFC4646.
580 
581   @retval the index of language in the language codes.
582 
583 **/
584 UINTN
GetIndexFromSupportedLangCodes(IN CHAR8 * SupportedLang,IN CHAR8 * Lang,IN BOOLEAN Iso639Language)585 GetIndexFromSupportedLangCodes(
586   IN  CHAR8            *SupportedLang,
587   IN  CHAR8            *Lang,
588   IN  BOOLEAN          Iso639Language
589   )
590 {
591   UINTN    Index;
592   UINTN    CompareLength;
593   UINTN    LanguageLength;
594 
595   if (Iso639Language) {
596     CompareLength = ISO_639_2_ENTRY_SIZE;
597     for (Index = 0; Index < AsciiStrLen (SupportedLang); Index += CompareLength) {
598       if (AsciiStrnCmp (Lang, SupportedLang + Index, CompareLength) == 0) {
599         //
600         // Successfully find the index of Lang string in SupportedLang string.
601         //
602         Index = Index / CompareLength;
603         return Index;
604       }
605     }
606     ASSERT (FALSE);
607     return 0;
608   } else {
609     //
610     // Compare RFC4646 language code
611     //
612     Index = 0;
613     for (LanguageLength = 0; Lang[LanguageLength] != '\0'; LanguageLength++);
614 
615     for (Index = 0; *SupportedLang != '\0'; Index++, SupportedLang += CompareLength) {
616       //
617       // Skip ';' characters in SupportedLang
618       //
619       for (; *SupportedLang != '\0' && *SupportedLang == ';'; SupportedLang++);
620       //
621       // Determine the length of the next language code in SupportedLang
622       //
623       for (CompareLength = 0; SupportedLang[CompareLength] != '\0' && SupportedLang[CompareLength] != ';'; CompareLength++);
624 
625       if ((CompareLength == LanguageLength) &&
626           (AsciiStrnCmp (Lang, SupportedLang, CompareLength) == 0)) {
627         //
628         // Successfully find the index of Lang string in SupportedLang string.
629         //
630         return Index;
631       }
632     }
633     ASSERT (FALSE);
634     return 0;
635   }
636 }
637 
638 /**
639   Get language string from supported language codes according to index.
640 
641   This code is used to get corresponding language string in supported language codes. It can handle
642   RFC4646 and ISO639 language tags.
643   In ISO639 language tags, take 3-characters as a delimitation. Find language string according to the index.
644   In RFC4646 language tags, take semicolon as a delimitation. Find language string according to the index.
645 
646   For example:
647     SupportedLang  = "engfraengfra"
648     Index          = "1"
649     Iso639Language = TRUE
650   The return value is "fra".
651   Another example:
652     SupportedLang  = "en;fr;en-US;fr-FR"
653     Index          = "1"
654     Iso639Language = FALSE
655   The return value is "fr".
656 
657   @param  SupportedLang               Platform supported language codes.
658   @param  Index                       the index in supported language codes.
659   @param  Iso639Language              A bool value to signify if the handler is operated on ISO639 or RFC4646.
660 
661   @retval the language string in the language codes.
662 
663 **/
664 CHAR8 *
GetLangFromSupportedLangCodes(IN CHAR8 * SupportedLang,IN UINTN Index,IN BOOLEAN Iso639Language)665 GetLangFromSupportedLangCodes (
666   IN  CHAR8            *SupportedLang,
667   IN  UINTN            Index,
668   IN  BOOLEAN          Iso639Language
669 )
670 {
671   UINTN    SubIndex;
672   UINTN    CompareLength;
673   CHAR8    *Supported;
674 
675   SubIndex  = 0;
676   Supported = SupportedLang;
677   if (Iso639Language) {
678     //
679     // according to the index of Lang string in SupportedLang string to get the language.
680     // As this code will be invoked in RUNTIME, therefore there is not memory allocate/free operation.
681     // In driver entry, it pre-allocates a runtime attribute memory to accommodate this string.
682     //
683     CompareLength = ISO_639_2_ENTRY_SIZE;
684     mGlobal->Lang[CompareLength] = '\0';
685     return CopyMem (mGlobal->Lang, SupportedLang + Index * CompareLength, CompareLength);
686 
687   } else {
688     while (TRUE) {
689       //
690       // take semicolon as delimitation, sequentially traverse supported language codes.
691       //
692       for (CompareLength = 0; *Supported != ';' && *Supported != '\0'; CompareLength++) {
693         Supported++;
694       }
695       if ((*Supported == '\0') && (SubIndex != Index)) {
696         //
697         // Have completed the traverse, but not find corrsponding string.
698         // This case is not allowed to happen.
699         //
700         ASSERT(FALSE);
701         return NULL;
702       }
703       if (SubIndex == Index) {
704         //
705         // according to the index of Lang string in SupportedLang string to get the language.
706         // As this code will be invoked in RUNTIME, therefore there is not memory allocate/free operation.
707         // In driver entry, it pre-allocates a runtime attribute memory to accommodate this string.
708         //
709         mGlobal->PlatformLang[CompareLength] = '\0';
710         return CopyMem (mGlobal->PlatformLang, Supported - CompareLength, CompareLength);
711       }
712       SubIndex++;
713 
714       //
715       // Skip ';' characters in Supported
716       //
717       for (; *Supported != '\0' && *Supported == ';'; Supported++);
718     }
719   }
720 }
721 
722 /**
723   Returns a pointer to an allocated buffer that contains the best matching language
724   from a set of supported languages.
725 
726   This function supports both ISO 639-2 and RFC 4646 language codes, but language
727   code types may not be mixed in a single call to this function. This function
728   supports a variable argument list that allows the caller to pass in a prioritized
729   list of language codes to test against all the language codes in SupportedLanguages.
730 
731   If SupportedLanguages is NULL, then ASSERT().
732 
733   @param[in]  SupportedLanguages  A pointer to a Null-terminated ASCII string that
734                                   contains a set of language codes in the format
735                                   specified by Iso639Language.
736   @param[in]  Iso639Language      If TRUE, then all language codes are assumed to be
737                                   in ISO 639-2 format.  If FALSE, then all language
738                                   codes are assumed to be in RFC 4646 language format
739   @param[in]  ...                 A variable argument list that contains pointers to
740                                   Null-terminated ASCII strings that contain one or more
741                                   language codes in the format specified by Iso639Language.
742                                   The first language code from each of these language
743                                   code lists is used to determine if it is an exact or
744                                   close match to any of the language codes in
745                                   SupportedLanguages.  Close matches only apply to RFC 4646
746                                   language codes, and the matching algorithm from RFC 4647
747                                   is used to determine if a close match is present.  If
748                                   an exact or close match is found, then the matching
749                                   language code from SupportedLanguages is returned.  If
750                                   no matches are found, then the next variable argument
751                                   parameter is evaluated.  The variable argument list
752                                   is terminated by a NULL.
753 
754   @retval NULL   The best matching language could not be found in SupportedLanguages.
755   @retval NULL   There are not enough resources available to return the best matching
756                  language.
757   @retval Other  A pointer to a Null-terminated ASCII string that is the best matching
758                  language in SupportedLanguages.
759 
760 **/
761 CHAR8 *
762 EFIAPI
VariableGetBestLanguage(IN CONST CHAR8 * SupportedLanguages,IN BOOLEAN Iso639Language,...)763 VariableGetBestLanguage (
764   IN CONST CHAR8  *SupportedLanguages,
765   IN BOOLEAN      Iso639Language,
766   ...
767   )
768 {
769   VA_LIST      Args;
770   CHAR8        *Language;
771   UINTN        CompareLength;
772   UINTN        LanguageLength;
773   CONST CHAR8  *Supported;
774   CHAR8        *Buffer;
775 
776   ASSERT (SupportedLanguages != NULL);
777 
778   VA_START (Args, Iso639Language);
779   while ((Language = VA_ARG (Args, CHAR8 *)) != NULL) {
780     //
781     // Default to ISO 639-2 mode
782     //
783     CompareLength  = 3;
784     LanguageLength = MIN (3, AsciiStrLen (Language));
785 
786     //
787     // If in RFC 4646 mode, then determine the length of the first RFC 4646 language code in Language
788     //
789     if (!Iso639Language) {
790       for (LanguageLength = 0; Language[LanguageLength] != 0 && Language[LanguageLength] != ';'; LanguageLength++);
791     }
792 
793     //
794     // Trim back the length of Language used until it is empty
795     //
796     while (LanguageLength > 0) {
797       //
798       // Loop through all language codes in SupportedLanguages
799       //
800       for (Supported = SupportedLanguages; *Supported != '\0'; Supported += CompareLength) {
801         //
802         // In RFC 4646 mode, then Loop through all language codes in SupportedLanguages
803         //
804         if (!Iso639Language) {
805           //
806           // Skip ';' characters in Supported
807           //
808           for (; *Supported != '\0' && *Supported == ';'; Supported++);
809           //
810           // Determine the length of the next language code in Supported
811           //
812           for (CompareLength = 0; Supported[CompareLength] != 0 && Supported[CompareLength] != ';'; CompareLength++);
813           //
814           // If Language is longer than the Supported, then skip to the next language
815           //
816           if (LanguageLength > CompareLength) {
817             continue;
818           }
819         }
820         //
821         // See if the first LanguageLength characters in Supported match Language
822         //
823         if (AsciiStrnCmp (Supported, Language, LanguageLength) == 0) {
824           VA_END (Args);
825 
826           Buffer = Iso639Language ? mGlobal->Lang : mGlobal->PlatformLang;
827           Buffer[CompareLength] = '\0';
828           return CopyMem (Buffer, Supported, CompareLength);
829         }
830       }
831 
832       if (Iso639Language) {
833         //
834         // If ISO 639 mode, then each language can only be tested once
835         //
836         LanguageLength = 0;
837       } else {
838         //
839         // If RFC 4646 mode, then trim Language from the right to the next '-' character
840         //
841         for (LanguageLength--; LanguageLength > 0 && Language[LanguageLength] != '-'; LanguageLength--);
842       }
843     }
844   }
845   VA_END (Args);
846 
847   //
848   // No matches were found
849   //
850   return NULL;
851 }
852 
853 /**
854   Hook the operations in PlatformLangCodes, LangCodes, PlatformLang and Lang.
855 
856   When setting Lang/LangCodes, simultaneously update PlatformLang/PlatformLangCodes.
857 
858   According to UEFI spec, PlatformLangCodes/LangCodes are only set once in firmware initialization,
859   and are read-only. Therefore, in variable driver, only store the original value for other use.
860 
861   @param[in] VariableName       Name of variable
862 
863   @param[in] Data               Variable data
864 
865   @param[in] DataSize           Size of data. 0 means delete
866 
867 **/
868 VOID
AutoUpdateLangVariable(IN CHAR16 * VariableName,IN VOID * Data,IN UINTN DataSize)869 AutoUpdateLangVariable(
870   IN  CHAR16             *VariableName,
871   IN  VOID               *Data,
872   IN  UINTN              DataSize
873   )
874 {
875   EFI_STATUS             Status;
876   CHAR8                  *BestPlatformLang;
877   CHAR8                  *BestLang;
878   UINTN                  Index;
879   UINT32                 Attributes;
880   VARIABLE_POINTER_TRACK Variable;
881   BOOLEAN                SetLanguageCodes;
882 
883   //
884   // Don't do updates for delete operation
885   //
886   if (DataSize == 0) {
887     return;
888   }
889 
890   SetLanguageCodes = FALSE;
891 
892   if (StrCmp (VariableName, L"PlatformLangCodes") == 0) {
893     //
894     // PlatformLangCodes is a volatile variable, so it can not be updated at runtime.
895     //
896     if (EfiAtRuntime ()) {
897       return;
898     }
899 
900     SetLanguageCodes = TRUE;
901 
902     //
903     // According to UEFI spec, PlatformLangCodes is only set once in firmware initialization, and is read-only
904     // Therefore, in variable driver, only store the original value for other use.
905     //
906     if (mGlobal->PlatformLangCodes != NULL) {
907       FreePool (mGlobal->PlatformLangCodes);
908     }
909     mGlobal->PlatformLangCodes = AllocateRuntimeCopyPool (DataSize, Data);
910     ASSERT (mGlobal->PlatformLangCodes != NULL);
911 
912     //
913     // PlatformLang holds a single language from PlatformLangCodes,
914     // so the size of PlatformLangCodes is enough for the PlatformLang.
915     //
916     if (mGlobal->PlatformLang != NULL) {
917       FreePool (mGlobal->PlatformLang);
918     }
919     mGlobal->PlatformLang = AllocateRuntimePool (DataSize);
920     ASSERT (mGlobal->PlatformLang != NULL);
921 
922   } else if (StrCmp (VariableName, L"LangCodes") == 0) {
923     //
924     // LangCodes is a volatile variable, so it can not be updated at runtime.
925     //
926     if (EfiAtRuntime ()) {
927       return;
928     }
929 
930     SetLanguageCodes = TRUE;
931 
932     //
933     // According to UEFI spec, LangCodes is only set once in firmware initialization, and is read-only
934     // Therefore, in variable driver, only store the original value for other use.
935     //
936     if (mGlobal->LangCodes != NULL) {
937       FreePool (mGlobal->LangCodes);
938     }
939     mGlobal->LangCodes = AllocateRuntimeCopyPool (DataSize, Data);
940     ASSERT (mGlobal->LangCodes != NULL);
941   }
942 
943   if (SetLanguageCodes
944       && (mGlobal->PlatformLangCodes != NULL)
945       && (mGlobal->LangCodes != NULL)) {
946     //
947     // Update Lang if PlatformLang is already set
948     // Update PlatformLang if Lang is already set
949     //
950     Status = FindVariable (L"PlatformLang", &gEfiGlobalVariableGuid, &Variable);
951     if (!EFI_ERROR (Status)) {
952       //
953       // Update Lang
954       //
955       VariableName = L"PlatformLang";
956       Data         = GetVariableDataPtr (Variable.CurrPtr);
957       DataSize     = Variable.CurrPtr->DataSize;
958     } else {
959       Status = FindVariable (L"Lang", &gEfiGlobalVariableGuid, &Variable);
960       if (!EFI_ERROR (Status)) {
961         //
962         // Update PlatformLang
963         //
964         VariableName = L"Lang";
965         Data         = GetVariableDataPtr (Variable.CurrPtr);
966         DataSize     = Variable.CurrPtr->DataSize;
967       } else {
968         //
969         // Neither PlatformLang nor Lang is set, directly return
970         //
971         return;
972       }
973     }
974   }
975 
976   //
977   // According to UEFI spec, "Lang" and "PlatformLang" is NV|BS|RT attributions.
978   //
979   Attributes = EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS;
980 
981   if (StrCmp (VariableName, L"PlatformLang") == 0) {
982     //
983     // Update Lang when PlatformLangCodes/LangCodes were set.
984     //
985     if ((mGlobal->PlatformLangCodes != NULL) && (mGlobal->LangCodes != NULL)) {
986       //
987       // When setting PlatformLang, firstly get most matched language string from supported language codes.
988       //
989       BestPlatformLang = VariableGetBestLanguage (mGlobal->PlatformLangCodes, FALSE, Data, NULL);
990       if (BestPlatformLang != NULL) {
991         //
992         // Get the corresponding index in language codes.
993         //
994         Index = GetIndexFromSupportedLangCodes (mGlobal->PlatformLangCodes, BestPlatformLang, FALSE);
995 
996         //
997         // Get the corresponding ISO639 language tag according to RFC4646 language tag.
998         //
999         BestLang = GetLangFromSupportedLangCodes (mGlobal->LangCodes, Index, TRUE);
1000 
1001         //
1002         // Successfully convert PlatformLang to Lang, and set the BestLang value into Lang variable simultaneously.
1003         //
1004         FindVariable(L"Lang", &gEfiGlobalVariableGuid, &Variable);
1005 
1006         Status = UpdateVariable (L"Lang", &gEfiGlobalVariableGuid, BestLang, ISO_639_2_ENTRY_SIZE + 1, Attributes, &Variable);
1007 
1008         DEBUG ((EFI_D_INFO, "Variable Driver Auto Update PlatformLang, PlatformLang:%a, Lang:%a\n", BestPlatformLang, BestLang));
1009 
1010         ASSERT_EFI_ERROR(Status);
1011       }
1012     }
1013 
1014   } else if (StrCmp (VariableName, L"Lang") == 0) {
1015     //
1016     // Update PlatformLang when PlatformLangCodes/LangCodes were set.
1017     //
1018     if ((mGlobal->PlatformLangCodes != NULL) && (mGlobal->LangCodes != NULL)) {
1019       //
1020       // When setting Lang, firstly get most matched language string from supported language codes.
1021       //
1022       BestLang = VariableGetBestLanguage (mGlobal->LangCodes, TRUE, Data, NULL);
1023       if (BestLang != NULL) {
1024         //
1025         // Get the corresponding index in language codes.
1026         //
1027         Index = GetIndexFromSupportedLangCodes (mGlobal->LangCodes, BestLang, TRUE);
1028 
1029         //
1030         // Get the corresponding RFC4646 language tag according to ISO639 language tag.
1031         //
1032         BestPlatformLang = GetLangFromSupportedLangCodes (mGlobal->PlatformLangCodes, Index, FALSE);
1033 
1034         //
1035         // Successfully convert Lang to PlatformLang, and set the BestPlatformLang value into PlatformLang variable simultaneously.
1036         //
1037         FindVariable(L"PlatformLang", &gEfiGlobalVariableGuid, &Variable);
1038 
1039         Status = UpdateVariable (L"PlatformLang", &gEfiGlobalVariableGuid, BestPlatformLang,
1040                                  AsciiStrSize (BestPlatformLang), Attributes, &Variable);
1041 
1042         DEBUG ((EFI_D_INFO, "Variable Driver Auto Update Lang, Lang:%a, PlatformLang:%a\n", BestLang, BestPlatformLang));
1043         ASSERT_EFI_ERROR (Status);
1044       }
1045     }
1046   }
1047 }
1048 
1049 /**
1050   Update the variable region with Variable information. These are the same
1051   arguments as the EFI Variable services.
1052 
1053   @param[in] VariableName       Name of variable
1054 
1055   @param[in] VendorGuid         Guid of variable
1056 
1057   @param[in] Data               Variable data
1058 
1059   @param[in] DataSize           Size of data. 0 means delete
1060 
1061   @param[in] Attributes         Attribues of the variable
1062 
1063   @param[in] Variable           The variable information which is used to keep track of variable usage.
1064 
1065   @retval EFI_SUCCESS           The update operation is success.
1066 
1067   @retval EFI_OUT_OF_RESOURCES  Variable region is full, can not write other data into this region.
1068 
1069 **/
1070 EFI_STATUS
1071 EFIAPI
UpdateVariable(IN CHAR16 * VariableName,IN EFI_GUID * VendorGuid,IN VOID * Data,IN UINTN DataSize,IN UINT32 Attributes OPTIONAL,IN VARIABLE_POINTER_TRACK * Variable)1072 UpdateVariable (
1073   IN      CHAR16                 *VariableName,
1074   IN      EFI_GUID               *VendorGuid,
1075   IN      VOID                   *Data,
1076   IN      UINTN                  DataSize,
1077   IN      UINT32                 Attributes OPTIONAL,
1078   IN      VARIABLE_POINTER_TRACK *Variable
1079   )
1080 {
1081   EFI_STATUS                          Status;
1082   VARIABLE_HEADER                     *NextVariable;
1083   UINTN                               VarNameOffset;
1084   UINTN                               VarDataOffset;
1085   UINTN                               VarNameSize;
1086   UINTN                               VarSize;
1087   UINT8                               State;
1088   BOOLEAN                             Reclaimed;
1089   VARIABLE_STORAGE_TYPE               StorageType;
1090 
1091   Reclaimed         = FALSE;
1092 
1093   if (Variable->CurrPtr != NULL) {
1094     //
1095     // Update/Delete existing variable
1096     //
1097 
1098     if (EfiAtRuntime ()) {
1099       //
1100       // If EfiAtRuntime and the variable is Volatile and Runtime Access,
1101       // the volatile is ReadOnly, and SetVariable should be aborted and
1102       // return EFI_WRITE_PROTECTED.
1103       //
1104       if (Variable->Type == Volatile) {
1105         return EFI_WRITE_PROTECTED;
1106       }
1107       //
1108       // Only variable have NV attribute can be updated/deleted in Runtime
1109       //
1110       if (!(Variable->CurrPtr->Attributes & EFI_VARIABLE_NON_VOLATILE)) {
1111         return EFI_INVALID_PARAMETER;
1112       }
1113     }
1114 
1115     //
1116     // Setting a data variable with no access, or zero DataSize attributes
1117     // specified causes it to be deleted.
1118     //
1119     if (DataSize == 0 || (Attributes & (EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS)) == 0) {
1120       //
1121       // Found this variable in storage
1122       //
1123       State = Variable->CurrPtr->State;
1124       State &= VAR_DELETED;
1125 
1126       Status = mGlobal->VariableStore[Variable->Type]->Write (
1127                                                         mGlobal->VariableStore[Variable->Type],
1128                                                         VARIABLE_MEMBER_OFFSET (State, (UINTN) Variable->CurrPtr - (UINTN) Variable->StartPtr),
1129                                                         sizeof (Variable->CurrPtr->State),
1130                                                         &State
1131                                                         );
1132       //
1133       // NOTE: Write operation at least can write data to memory cache
1134       //       Discard file writing failure here.
1135       //
1136       return EFI_SUCCESS;
1137     }
1138 
1139     //
1140     // Found this variable in storage
1141     // If the variable is marked valid and the same data has been passed in
1142     // then return to the caller immediately.
1143     //
1144     if ((Variable->CurrPtr->DataSize == DataSize) &&
1145         (CompareMem (Data, GetVariableDataPtr (Variable->CurrPtr), DataSize) == 0)
1146           ) {
1147       return EFI_SUCCESS;
1148     } else if ((Variable->CurrPtr->State == VAR_ADDED) ||
1149                (Variable->CurrPtr->State == (VAR_ADDED & VAR_IN_DELETED_TRANSITION))) {
1150       //
1151       // Mark the old variable as in delete transition
1152       //
1153       State = Variable->CurrPtr->State;
1154       State &= VAR_IN_DELETED_TRANSITION;
1155 
1156       Status = mGlobal->VariableStore[Variable->Type]->Write (
1157                                                         mGlobal->VariableStore[Variable->Type],
1158                                                         VARIABLE_MEMBER_OFFSET (State, (UINTN) Variable->CurrPtr - (UINTN) Variable->StartPtr),
1159                                                         sizeof (Variable->CurrPtr->State),
1160                                                         &State
1161                                                         );
1162       //
1163       // NOTE: Write operation at least can write data to memory cache
1164       //       Discard file writing failure here.
1165       //
1166     }
1167   } else {
1168     //
1169     // Create a new variable
1170     //
1171 
1172     //
1173     // Make sure we are trying to create a new variable.
1174     // Setting a data variable with no access, or zero DataSize attributes means to delete it.
1175     //
1176     if (DataSize == 0 || (Attributes & (EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS)) == 0) {
1177       return EFI_NOT_FOUND;
1178     }
1179     //
1180     // Only variable have NV|RT attribute can be created in Runtime
1181     //
1182     if (EfiAtRuntime () &&
1183         (!(Attributes & EFI_VARIABLE_RUNTIME_ACCESS) || !(Attributes & EFI_VARIABLE_NON_VOLATILE))) {
1184       return EFI_INVALID_PARAMETER;
1185     }
1186 
1187   }
1188 
1189   //
1190   // Function part - create a new variable and copy the data.
1191   // Both update a variable and create a variable will come here.
1192   // We can firstly write all the data in memory, then write them to file
1193   // This can reduce the times of write operation
1194   //
1195 
1196   NextVariable = (VARIABLE_HEADER *) mGlobal->Scratch;
1197 
1198   NextVariable->StartId     = VARIABLE_DATA;
1199   NextVariable->Attributes  = Attributes;
1200   NextVariable->State       = VAR_ADDED;
1201   NextVariable->Reserved    = 0;
1202   VarNameOffset             = sizeof (VARIABLE_HEADER);
1203   VarNameSize               = StrSize (VariableName);
1204   CopyMem (
1205     (UINT8 *) ((UINTN) NextVariable + VarNameOffset),
1206     VariableName,
1207     VarNameSize
1208     );
1209   VarDataOffset = VarNameOffset + VarNameSize + GET_PAD_SIZE (VarNameSize);
1210   CopyMem (
1211     (UINT8 *) ((UINTN) NextVariable + VarDataOffset),
1212     Data,
1213     DataSize
1214     );
1215   CopyMem (&NextVariable->VendorGuid, VendorGuid, sizeof (EFI_GUID));
1216   //
1217   // There will be pad bytes after Data, the NextVariable->NameSize and
1218   // NextVariable->DataSize should not include pad size so that variable
1219   // service can get actual size in GetVariable
1220   //
1221   NextVariable->NameSize  = (UINT32)VarNameSize;
1222   NextVariable->DataSize  = (UINT32)DataSize;
1223 
1224   //
1225   // The actual size of the variable that stores in storage should
1226   // include pad size.
1227   // VarDataOffset: offset from begin of current variable header
1228   //
1229   VarSize = VarDataOffset + DataSize + GET_PAD_SIZE (DataSize);
1230 
1231   StorageType = (Attributes & EFI_VARIABLE_NON_VOLATILE) ? NonVolatile : Volatile;
1232 
1233   if ((UINT32) (VarSize + mGlobal->LastVariableOffset[StorageType]) >
1234       ((VARIABLE_STORE_HEADER *) mGlobal->VariableBase[StorageType])->Size
1235       ) {
1236     if ((StorageType == NonVolatile) && EfiAtRuntime ()) {
1237       return EFI_OUT_OF_RESOURCES;
1238     }
1239     //
1240     // Perform garbage collection & reclaim operation
1241     //
1242     Status = Reclaim (StorageType, Variable->CurrPtr);
1243     if (EFI_ERROR (Status)) {
1244       //
1245       // Reclaim error
1246       // we cannot restore to original state, fetal error, report to user
1247       //
1248       DEBUG ((EFI_D_ERROR, "FSVariable: Recalim error (fetal error) - %r\n", Status));
1249       return Status;
1250     }
1251     //
1252     // If still no enough space, return out of resources
1253     //
1254     if ((UINT32) (VarSize + mGlobal->LastVariableOffset[StorageType]) >
1255         ((VARIABLE_STORE_HEADER *) mGlobal->VariableBase[StorageType])->Size
1256        ) {
1257       return EFI_OUT_OF_RESOURCES;
1258     }
1259 
1260     Reclaimed = TRUE;
1261   }
1262   Status = mGlobal->VariableStore[StorageType]->Write (
1263                                                   mGlobal->VariableStore[StorageType],
1264                                                   mGlobal->LastVariableOffset[StorageType],
1265                                                   VarSize,
1266                                                   NextVariable
1267                                                   );
1268   //
1269   // NOTE: Write operation at least can write data to memory cache
1270   //       Discard file writing failure here.
1271   //
1272   mGlobal->LastVariableOffset[StorageType] += VarSize;
1273 
1274   if ((Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) != 0) {
1275     mGlobal->HwErrVariableTotalSize += VarSize;
1276   } else {
1277     mGlobal->CommonVariableTotalSize += VarSize;
1278   }
1279 
1280   //
1281   // Mark the old variable as deleted
1282   //
1283   if (!Reclaimed && !EFI_ERROR (Status) && Variable->CurrPtr != NULL) {
1284     State = Variable->CurrPtr->State;
1285     State &= VAR_DELETED;
1286 
1287     Status = mGlobal->VariableStore[StorageType]->Write (
1288                                                     mGlobal->VariableStore[StorageType],
1289                                                     VARIABLE_MEMBER_OFFSET (State, (UINTN) Variable->CurrPtr - (UINTN) Variable->StartPtr),
1290                                                     sizeof (Variable->CurrPtr->State),
1291                                                     &State
1292                                                     );
1293     //
1294     // NOTE: Write operation at least can write data to memory cache
1295     //       Discard file writing failure here.
1296     //
1297   }
1298   return EFI_SUCCESS;
1299 }
1300 
1301 EFI_STATUS
1302 EFIAPI
DuetGetVariable(IN CHAR16 * VariableName,IN EFI_GUID * VendorGuid,OUT UINT32 * Attributes OPTIONAL,IN OUT UINTN * DataSize,OUT VOID * Data OPTIONAL)1303 DuetGetVariable (
1304   IN      CHAR16            *VariableName,
1305   IN      EFI_GUID          *VendorGuid,
1306   OUT     UINT32            *Attributes OPTIONAL,
1307   IN OUT  UINTN             *DataSize,
1308   OUT     VOID              *Data OPTIONAL
1309   )
1310 /*++
1311 
1312 Routine Description:
1313 
1314   This code finds variable in storage blocks (Volatile or Non-Volatile)
1315 
1316 Arguments:
1317 
1318   VariableName                    Name of Variable to be found
1319   VendorGuid                      Variable vendor GUID
1320   Attributes OPTIONAL             Attribute value of the variable found
1321   DataSize                        Size of Data found. If size is less than the
1322                                   data, this value contains the required size.
1323   Data                            The buffer to return the contents of the variable. May be NULL
1324                                   with a zero DataSize in order to determine the size buffer needed.
1325 
1326 Returns:
1327 
1328   EFI STATUS
1329 
1330 --*/
1331 {
1332   VARIABLE_POINTER_TRACK  Variable;
1333   UINTN                   VarDataSize;
1334   EFI_STATUS              Status;
1335 
1336   if (VariableName == NULL || VendorGuid == NULL || DataSize == NULL) {
1337     return EFI_INVALID_PARAMETER;
1338   }
1339 
1340   if (VariableName[0] == 0) {
1341     return EFI_NOT_FOUND;
1342   }
1343 
1344   //
1345   // Find existing variable
1346   //
1347   Status = FindVariable (VariableName, VendorGuid, &Variable);
1348 
1349   if (Variable.CurrPtr == NULL || EFI_ERROR (Status)) {
1350     return Status;
1351   }
1352   //
1353   // Get data size
1354   //
1355   VarDataSize = Variable.CurrPtr->DataSize;
1356   if (*DataSize >= VarDataSize) {
1357     if (Data == NULL) {
1358       return EFI_INVALID_PARAMETER;
1359     }
1360     CopyMem (Data, GetVariableDataPtr (Variable.CurrPtr), VarDataSize);
1361 
1362     if (Attributes != NULL) {
1363       *Attributes = Variable.CurrPtr->Attributes;
1364     }
1365 
1366     *DataSize = VarDataSize;
1367 
1368     return EFI_SUCCESS;
1369   } else {
1370     *DataSize = VarDataSize;
1371     return EFI_BUFFER_TOO_SMALL;
1372   }
1373 }
1374 
1375 EFI_STATUS
1376 EFIAPI
GetNextVariableName(IN OUT UINTN * VariableNameSize,IN OUT CHAR16 * VariableName,IN OUT EFI_GUID * VendorGuid)1377 GetNextVariableName (
1378   IN OUT  UINTN             *VariableNameSize,
1379   IN OUT  CHAR16            *VariableName,
1380   IN OUT  EFI_GUID          *VendorGuid
1381   )
1382 /*++
1383 
1384 Routine Description:
1385 
1386   This code Finds the Next available variable
1387 
1388 Arguments:
1389 
1390   VariableNameSize            Size of the variable
1391   VariableName                Pointer to variable name
1392   VendorGuid                  Variable Vendor Guid
1393 
1394 Returns:
1395 
1396   EFI STATUS
1397 
1398 --*/
1399 {
1400   VARIABLE_POINTER_TRACK  Variable;
1401   UINTN                   VarNameSize;
1402   EFI_STATUS              Status;
1403 
1404   if (VariableNameSize == NULL || VariableName == NULL || VendorGuid == NULL) {
1405     return EFI_INVALID_PARAMETER;
1406   }
1407 
1408   Status = FindVariable (VariableName, VendorGuid, &Variable);
1409 
1410   if (Variable.CurrPtr == NULL || EFI_ERROR (Status)) {
1411     return Status;
1412   }
1413 
1414   if (VariableName[0] != 0) {
1415     //
1416     // If variable name is not NULL, get next variable
1417     //
1418     Variable.CurrPtr = GetNextVariablePtr (Variable.CurrPtr);
1419   }
1420 
1421   while (TRUE) {
1422     //
1423     // The order we find variable is: 1). NonVolatile; 2). Volatile
1424     // If both volatile and non-volatile variable store are parsed,
1425     // return not found
1426     //
1427     if (Variable.CurrPtr >= Variable.EndPtr || Variable.CurrPtr == NULL) {
1428       if (Variable.Type == Volatile) {
1429         //
1430         // Since we met the end of Volatile storage, we have parsed all the stores.
1431         //
1432         return EFI_NOT_FOUND;
1433       }
1434 
1435       //
1436       // End of NonVolatile, continue to parse Volatile
1437       //
1438       Variable.Type = Volatile;
1439       Variable.StartPtr = (VARIABLE_HEADER *) ((VARIABLE_STORE_HEADER *) mGlobal->VariableBase[Volatile] + 1);
1440       Variable.EndPtr   = (VARIABLE_HEADER *) GetEndPointer ((VARIABLE_STORE_HEADER *) mGlobal->VariableBase[Volatile]);
1441 
1442       Variable.CurrPtr = Variable.StartPtr;
1443       if (!IsValidVariableHeader (Variable.CurrPtr)) {
1444         continue;
1445       }
1446     }
1447     //
1448     // Variable is found
1449     //
1450     if (IsValidVariableHeader (Variable.CurrPtr) &&
1451         ((Variable.CurrPtr->State == VAR_ADDED) ||
1452          (Variable.CurrPtr->State == (VAR_ADDED & VAR_IN_DELETED_TRANSITION)))) {
1453       if (!EfiAtRuntime () || (Variable.CurrPtr->Attributes & EFI_VARIABLE_RUNTIME_ACCESS)) {
1454         VarNameSize = Variable.CurrPtr->NameSize;
1455         if (VarNameSize <= *VariableNameSize) {
1456           CopyMem (
1457             VariableName,
1458             GET_VARIABLE_NAME_PTR (Variable.CurrPtr),
1459             VarNameSize
1460             );
1461           CopyMem (
1462             VendorGuid,
1463             &Variable.CurrPtr->VendorGuid,
1464             sizeof (EFI_GUID)
1465             );
1466           Status = EFI_SUCCESS;
1467         } else {
1468           Status = EFI_BUFFER_TOO_SMALL;
1469         }
1470 
1471         *VariableNameSize = VarNameSize;
1472         return Status;
1473       }
1474     }
1475 
1476     Variable.CurrPtr = GetNextVariablePtr (Variable.CurrPtr);
1477   }
1478 }
1479 
1480 EFI_STATUS
1481 EFIAPI
SetVariable(IN CHAR16 * VariableName,IN EFI_GUID * VendorGuid,IN UINT32 Attributes,IN UINTN DataSize,IN VOID * Data)1482 SetVariable (
1483   IN CHAR16                  *VariableName,
1484   IN EFI_GUID                *VendorGuid,
1485   IN UINT32                  Attributes,
1486   IN UINTN                   DataSize,
1487   IN VOID                    *Data
1488   )
1489 /*++
1490 
1491 Routine Description:
1492 
1493   This code sets variable in storage blocks (Volatile or Non-Volatile)
1494 
1495 Arguments:
1496 
1497   VariableName                    Name of Variable to be found
1498   VendorGuid                      Variable vendor GUID
1499   Attributes                      Attribute value of the variable found
1500   DataSize                        Size of Data found. If size is less than the
1501                                   data, this value contains the required size.
1502   Data                            Data pointer
1503 
1504 Returns:
1505 
1506   EFI_INVALID_PARAMETER           - Invalid parameter
1507   EFI_SUCCESS                     - Set successfully
1508   EFI_OUT_OF_RESOURCES            - Resource not enough to set variable
1509   EFI_NOT_FOUND                   - Not found
1510   EFI_DEVICE_ERROR                - Variable can not be saved due to hardware failure
1511   EFI_WRITE_PROTECTED             - Variable is read-only
1512 
1513 --*/
1514 {
1515   VARIABLE_POINTER_TRACK  Variable;
1516   EFI_STATUS              Status;
1517 
1518   //
1519   // Check input parameters
1520   //
1521   if (VariableName == NULL || VariableName[0] == 0 || VendorGuid == NULL) {
1522     return EFI_INVALID_PARAMETER;
1523   }
1524 
1525   if (DataSize != 0 && Data == NULL) {
1526     return EFI_INVALID_PARAMETER;
1527   }
1528 
1529   //
1530   // Not support authenticated variable write yet.
1531   //
1532   if ((Attributes & EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS) != 0) {
1533     return EFI_INVALID_PARAMETER;
1534   }
1535 
1536   //
1537   //  Make sure if runtime bit is set, boot service bit is set also
1538   //
1539   if ((Attributes & (EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS)) == EFI_VARIABLE_RUNTIME_ACCESS) {
1540     return EFI_INVALID_PARAMETER;
1541   }
1542 
1543   //
1544   //  The size of the VariableName, including the Unicode Null in bytes plus
1545   //  the DataSize is limited to maximum size of PcdGet32 (PcdMaxHardwareErrorVariableSize)
1546   //  bytes for HwErrRec, and PcdGet32 (PcdMaxVariableSize) bytes for the others.
1547   //
1548   if ((Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == EFI_VARIABLE_HARDWARE_ERROR_RECORD) {
1549     if ((DataSize > PcdGet32(PcdMaxHardwareErrorVariableSize)) ||
1550         (sizeof (VARIABLE_HEADER) + StrSize (VariableName) + DataSize > PcdGet32(PcdMaxHardwareErrorVariableSize))) {
1551       return EFI_INVALID_PARAMETER;
1552     }
1553     //
1554     // According to UEFI spec, HARDWARE_ERROR_RECORD variable name convention should be L"HwErrRecXXXX"
1555     //
1556     if (StrnCmp(VariableName, L"HwErrRec", StrLen(L"HwErrRec")) != 0) {
1557       return EFI_INVALID_PARAMETER;
1558     }
1559   } else {
1560     if ((DataSize > PcdGet32(PcdMaxVariableSize)) ||
1561         (sizeof (VARIABLE_HEADER) + StrSize (VariableName) + DataSize > PcdGet32(PcdMaxVariableSize))) {
1562       return EFI_INVALID_PARAMETER;
1563     }
1564   }
1565 
1566   //
1567   // Check whether the input variable is already existed
1568   //
1569   Status = FindVariable (VariableName, VendorGuid, &Variable);
1570 
1571   //
1572   // Hook the operation of setting PlatformLangCodes/PlatformLang and LangCodes/Lang
1573   //
1574   AutoUpdateLangVariable (VariableName, Data, DataSize);
1575 
1576   Status = UpdateVariable (VariableName, VendorGuid, Data, DataSize, Attributes, &Variable);
1577 
1578   return Status;
1579 }
1580 
1581 EFI_STATUS
1582 EFIAPI
QueryVariableInfo(IN UINT32 Attributes,OUT UINT64 * MaximumVariableStorageSize,OUT UINT64 * RemainingVariableStorageSize,OUT UINT64 * MaximumVariableSize)1583 QueryVariableInfo (
1584   IN  UINT32                 Attributes,
1585   OUT UINT64                 *MaximumVariableStorageSize,
1586   OUT UINT64                 *RemainingVariableStorageSize,
1587   OUT UINT64                 *MaximumVariableSize
1588   )
1589 /*++
1590 
1591 Routine Description:
1592 
1593   This code returns information about the EFI variables.
1594 
1595 Arguments:
1596 
1597   Attributes                      Attributes bitmask to specify the type of variables
1598                                   on which to return information.
1599   MaximumVariableStorageSize      Pointer to the maximum size of the storage space available
1600                                   for the EFI variables associated with the attributes specified.
1601   RemainingVariableStorageSize    Pointer to the remaining size of the storage space available
1602                                   for the EFI variables associated with the attributes specified.
1603   MaximumVariableSize             Pointer to the maximum size of the individual EFI variables
1604                                   associated with the attributes specified.
1605 
1606 Returns:
1607 
1608   EFI STATUS
1609   EFI_INVALID_PARAMETER           - An invalid combination of attribute bits was supplied.
1610   EFI_SUCCESS                     - Query successfully.
1611   EFI_UNSUPPORTED                 - The attribute is not supported on this platform.
1612 
1613 --*/
1614 {
1615   VARIABLE_HEADER        *Variable;
1616   VARIABLE_HEADER        *NextVariable;
1617   UINT64                 VariableSize;
1618   VARIABLE_STORE_HEADER  *VariableStoreHeader;
1619   UINT64                 CommonVariableTotalSize;
1620   UINT64                 HwErrVariableTotalSize;
1621 
1622   CommonVariableTotalSize = 0;
1623   HwErrVariableTotalSize = 0;
1624 
1625   if(MaximumVariableStorageSize == NULL || RemainingVariableStorageSize == NULL || MaximumVariableSize == NULL || Attributes == 0) {
1626     return EFI_INVALID_PARAMETER;
1627   }
1628 
1629   if((Attributes & (EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_HARDWARE_ERROR_RECORD)) == 0) {
1630     //
1631     // Make sure the Attributes combination is supported by the platform.
1632     //
1633     return EFI_UNSUPPORTED;
1634   } else if ((Attributes & (EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS)) == EFI_VARIABLE_RUNTIME_ACCESS) {
1635     //
1636     // Make sure if runtime bit is set, boot service bit is set also.
1637     //
1638     return EFI_INVALID_PARAMETER;
1639   } else if (EfiAtRuntime () && !(Attributes & EFI_VARIABLE_RUNTIME_ACCESS)) {
1640     //
1641     // Make sure RT Attribute is set if we are in Runtime phase.
1642     //
1643     return EFI_INVALID_PARAMETER;
1644   } else if ((Attributes & (EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_HARDWARE_ERROR_RECORD)) == EFI_VARIABLE_HARDWARE_ERROR_RECORD) {
1645     //
1646     // Make sure Hw Attribute is set with NV.
1647     //
1648     return EFI_INVALID_PARAMETER;
1649   } else if ((Attributes & EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS) != 0) {
1650     //
1651     // Not support authentiated variable write yet.
1652     //
1653     return EFI_UNSUPPORTED;
1654   }
1655 
1656   VariableStoreHeader = (VARIABLE_STORE_HEADER *) mGlobal->VariableBase[
1657                                 (Attributes & EFI_VARIABLE_NON_VOLATILE) ? NonVolatile : Volatile
1658                                 ];
1659   //
1660   // Now let's fill *MaximumVariableStorageSize *RemainingVariableStorageSize
1661   // with the storage size (excluding the storage header size).
1662   //
1663   *MaximumVariableStorageSize   = VariableStoreHeader->Size - sizeof (VARIABLE_STORE_HEADER);
1664 
1665   //
1666   // Harware error record variable needs larger size.
1667   //
1668   if ((Attributes & (EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_HARDWARE_ERROR_RECORD)) == (EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_HARDWARE_ERROR_RECORD)) {
1669     *MaximumVariableStorageSize = PcdGet32(PcdHwErrStorageSize);
1670     *MaximumVariableSize = PcdGet32(PcdMaxHardwareErrorVariableSize) - sizeof (VARIABLE_HEADER);
1671   } else {
1672     if ((Attributes & EFI_VARIABLE_NON_VOLATILE) != 0) {
1673       ASSERT (PcdGet32(PcdHwErrStorageSize) < VariableStoreHeader->Size);
1674       *MaximumVariableStorageSize = VariableStoreHeader->Size - sizeof (VARIABLE_STORE_HEADER) - PcdGet32(PcdHwErrStorageSize);
1675     }
1676 
1677     //
1678     // Let *MaximumVariableSize be PcdGet32(PcdMaxVariableSize) with the exception of the variable header size.
1679     //
1680     *MaximumVariableSize = PcdGet32(PcdMaxVariableSize) - sizeof (VARIABLE_HEADER);
1681   }
1682 
1683   //
1684   // Point to the starting address of the variables.
1685   //
1686   Variable = (VARIABLE_HEADER *) (VariableStoreHeader + 1);
1687 
1688   //
1689   // Now walk through the related variable store.
1690   //
1691   while ((Variable < GetEndPointer (VariableStoreHeader)) && IsValidVariableHeader (Variable)) {
1692     NextVariable = GetNextVariablePtr (Variable);
1693     VariableSize = (UINT64) (UINTN) NextVariable - (UINT64) (UINTN) Variable;
1694 
1695     if (EfiAtRuntime ()) {
1696       //
1697       // we don't take the state of the variables in mind
1698       // when calculating RemainingVariableStorageSize,
1699       // since the space occupied by variables not marked with
1700       // VAR_ADDED is not allowed to be reclaimed in Runtime.
1701       //
1702       if ((Variable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == EFI_VARIABLE_HARDWARE_ERROR_RECORD) {
1703         HwErrVariableTotalSize += VariableSize;
1704       } else {
1705         CommonVariableTotalSize += VariableSize;
1706       }
1707     } else {
1708       //
1709       // Only care about Variables with State VAR_ADDED,because
1710       // the space not marked as VAR_ADDED is reclaimable now.
1711       //
1712       if ((Variable->State == VAR_ADDED) || (Variable->State == (VAR_ADDED & VAR_IN_DELETED_TRANSITION))) {
1713         if ((Variable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == EFI_VARIABLE_HARDWARE_ERROR_RECORD) {
1714           HwErrVariableTotalSize += VariableSize;
1715         } else {
1716           CommonVariableTotalSize += VariableSize;
1717         }
1718       }
1719     }
1720 
1721     //
1722     // Go to the next one
1723     //
1724     Variable = NextVariable;
1725   }
1726 
1727   if ((Attributes  & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == EFI_VARIABLE_HARDWARE_ERROR_RECORD){
1728     *RemainingVariableStorageSize = *MaximumVariableStorageSize - HwErrVariableTotalSize;
1729   } else {
1730     *RemainingVariableStorageSize = *MaximumVariableStorageSize - CommonVariableTotalSize;
1731   }
1732 
1733   return EFI_SUCCESS;
1734 }
1735 
1736 EFI_STATUS
1737 EFIAPI
VariableServiceInitialize(IN EFI_HANDLE ImageHandle,IN EFI_SYSTEM_TABLE * SystemTable)1738 VariableServiceInitialize (
1739   IN EFI_HANDLE         ImageHandle,
1740   IN EFI_SYSTEM_TABLE   *SystemTable
1741   )
1742 /*++
1743 
1744 Routine Description:
1745   This function does initialization for variable services
1746 
1747 Arguments:
1748 
1749   ImageHandle   - The firmware allocated handle for the EFI image.
1750   SystemTable   - A pointer to the EFI System Table.
1751 
1752 Returns:
1753 
1754   Status code.
1755 
1756   EFI_NOT_FOUND     - Variable store area not found.
1757   EFI_SUCCESS       - Variable services successfully initialized.
1758 
1759 --*/
1760 {
1761   EFI_STATUS                      Status;
1762   EFI_HANDLE                      NewHandle;
1763   VS_DEV                          *Dev;
1764   EFI_PEI_HOB_POINTERS            GuidHob;
1765   VARIABLE_HEADER                 *Variable;
1766   VARIABLE_HEADER                 *NextVariable;
1767   VARIABLE_STORE_HEADER           *VariableStoreHeader;
1768   EFI_FLASH_MAP_FS_ENTRY_DATA     *FlashMapEntryData;
1769   EFI_FLASH_SUBAREA_ENTRY         VariableStoreEntry;
1770   UINT64                          BaseAddress;
1771   UINT64                          Length;
1772   EFI_GCD_MEMORY_SPACE_DESCRIPTOR GcdDescriptor;
1773 
1774   Status = gBS->AllocatePool (
1775                   EfiRuntimeServicesData,
1776                   (UINTN) sizeof (VARIABLE_GLOBAL),
1777                   (VOID**) &mGlobal
1778                   );
1779   if (EFI_ERROR (Status)) {
1780     return Status;
1781   }
1782 
1783   ZeroMem (mGlobal, (UINTN) sizeof (VARIABLE_GLOBAL));
1784 
1785   GuidHob.Raw = GetHobList ();
1786   FlashMapEntryData = NULL;
1787   while ((GuidHob.Raw = GetNextGuidHob (&gEfiFlashMapHobGuid, GuidHob.Raw)) != NULL) {
1788     FlashMapEntryData = (EFI_FLASH_MAP_FS_ENTRY_DATA *) GET_GUID_HOB_DATA (GuidHob.Guid);
1789     if (FlashMapEntryData->AreaType == EFI_FLASH_AREA_EFI_VARIABLES) {
1790       break;
1791     }
1792     GuidHob.Raw = GET_NEXT_HOB (GuidHob);
1793   }
1794 
1795   if (FlashMapEntryData == NULL) {
1796     DEBUG ((EFI_D_ERROR, "FSVariable: Could not find flash area for variable!\n"));
1797     Status = EFI_NOT_FOUND;
1798     return Status;
1799   }
1800 
1801   CopyMem(
1802     (VOID*)&VariableStoreEntry,
1803     (VOID*)&FlashMapEntryData->Entries[0],
1804     sizeof(EFI_FLASH_SUBAREA_ENTRY)
1805     );
1806 
1807   //
1808   // Mark the variable storage region of the FLASH as RUNTIME
1809   //
1810   BaseAddress = VariableStoreEntry.Base & (~EFI_PAGE_MASK);
1811   Length      = VariableStoreEntry.Length + (VariableStoreEntry.Base - BaseAddress);
1812   Length      = (Length + EFI_PAGE_SIZE - 1) & (~EFI_PAGE_MASK);
1813   Status      = gDS->GetMemorySpaceDescriptor (BaseAddress, &GcdDescriptor);
1814   if (EFI_ERROR (Status)) {
1815     Status = EFI_UNSUPPORTED;
1816     return Status;
1817   }
1818   Status = gDS->SetMemorySpaceAttributes (
1819                   BaseAddress,
1820                   Length,
1821                   GcdDescriptor.Attributes | EFI_MEMORY_RUNTIME
1822                   );
1823   if (EFI_ERROR (Status)) {
1824     Status = EFI_UNSUPPORTED;
1825     return Status;
1826   }
1827 
1828   Status = FileStorageConstructor (
1829              &mGlobal->VariableStore[NonVolatile],
1830              &mGlobal->GoVirtualChildEvent[NonVolatile],
1831              VariableStoreEntry.Base,
1832              (UINT32) VariableStoreEntry.Length,
1833              FlashMapEntryData->VolumeId,
1834              FlashMapEntryData->FilePath
1835              );
1836   ASSERT_EFI_ERROR (Status);
1837 
1838   //
1839   // Volatile Storage
1840   //
1841   Status = MemStorageConstructor (
1842              &mGlobal->VariableStore[Volatile],
1843              &mGlobal->GoVirtualChildEvent[Volatile],
1844              VOLATILE_VARIABLE_STORE_SIZE
1845              );
1846   ASSERT_EFI_ERROR (Status);
1847 
1848   //
1849   // Scratch
1850   //
1851   Status = gBS->AllocatePool (
1852                   EfiRuntimeServicesData,
1853                   VARIABLE_SCRATCH_SIZE,
1854                   &mGlobal->Scratch
1855                   );
1856   ASSERT_EFI_ERROR (Status);
1857 
1858   //
1859   // 1. NV Storage
1860   //
1861   Dev = DEV_FROM_THIS (mGlobal->VariableStore[NonVolatile]);
1862   VariableStoreHeader = (VARIABLE_STORE_HEADER *) VAR_DATA_PTR (Dev);
1863   if (GetVariableStoreStatus (VariableStoreHeader) == EfiValid) {
1864     if (~VariableStoreHeader->Size == 0) {
1865       VariableStoreHeader->Size = (UINT32) VariableStoreEntry.Length;
1866     }
1867   }
1868   //
1869   // Calculate LastVariableOffset
1870   //
1871   Variable = (VARIABLE_HEADER *) (VariableStoreHeader + 1);
1872   while (IsValidVariableHeader (Variable)) {
1873     UINTN VariableSize = 0;
1874     NextVariable = GetNextVariablePtr (Variable);
1875     VariableSize = NextVariable - Variable;
1876     if ((NextVariable->Attributes & (EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_HARDWARE_ERROR_RECORD)) == (EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_HARDWARE_ERROR_RECORD)) {
1877       mGlobal->HwErrVariableTotalSize += HEADER_ALIGN (VariableSize);
1878     } else {
1879       mGlobal->CommonVariableTotalSize += HEADER_ALIGN (VariableSize);
1880     }
1881     Variable = NextVariable;
1882   }
1883 
1884   mGlobal->LastVariableOffset[NonVolatile] = (UINTN) Variable - (UINTN) VariableStoreHeader;
1885   mGlobal->VariableBase[NonVolatile]       = VariableStoreHeader;
1886 
1887   //
1888   // Reclaim if remaining space is too small
1889   //
1890   if ((VariableStoreHeader->Size - mGlobal->LastVariableOffset[NonVolatile]) < VARIABLE_RECLAIM_THRESHOLD) {
1891     Status = Reclaim (NonVolatile, NULL);
1892     if (EFI_ERROR (Status)) {
1893       //
1894       // Reclaim error
1895       // we cannot restore to original state
1896       //
1897       DEBUG ((EFI_D_ERROR, "FSVariable: Reclaim error (fatal error) - %r\n", Status));
1898       ASSERT_EFI_ERROR (Status);
1899     }
1900   }
1901 
1902   //
1903   // 2. Volatile Storage
1904   //
1905   Dev = DEV_FROM_THIS (mGlobal->VariableStore[Volatile]);
1906   VariableStoreHeader = (VARIABLE_STORE_HEADER *) VAR_DATA_PTR (Dev);
1907   mGlobal->VariableBase[Volatile] = VAR_DATA_PTR (Dev);
1908   mGlobal->LastVariableOffset[Volatile] = sizeof (VARIABLE_STORE_HEADER);
1909   //
1910   // init store_header & body in memory.
1911   //
1912   mGlobal->VariableStore[Volatile]->Erase (mGlobal->VariableStore[Volatile]);
1913   mGlobal->VariableStore[Volatile]->Write (
1914                                    mGlobal->VariableStore[Volatile],
1915                                    0,
1916                                    sizeof (VARIABLE_STORE_HEADER),
1917                                    &mStoreHeaderTemplate
1918                                    );
1919 
1920 
1921   SystemTable->RuntimeServices->GetVariable         = DuetGetVariable;
1922   SystemTable->RuntimeServices->GetNextVariableName = GetNextVariableName;
1923   SystemTable->RuntimeServices->SetVariable         = SetVariable;
1924 
1925   SystemTable->RuntimeServices->QueryVariableInfo   = QueryVariableInfo;
1926 
1927   //
1928   // Now install the Variable Runtime Architectural Protocol on a new handle
1929   //
1930   NewHandle = NULL;
1931   Status = gBS->InstallMultipleProtocolInterfaces (
1932                   &NewHandle,
1933                   &gEfiVariableArchProtocolGuid,
1934                   NULL,
1935                   &gEfiVariableWriteArchProtocolGuid,
1936                   NULL,
1937                   NULL
1938                   );
1939   ASSERT_EFI_ERROR (Status);
1940 
1941   return Status;
1942 }
1943 
1944 
1945 
1946 VOID
1947 EFIAPI
OnVirtualAddressChangeFsv(IN EFI_EVENT Event,IN VOID * Context)1948 OnVirtualAddressChangeFsv (
1949   IN EFI_EVENT        Event,
1950   IN VOID             *Context
1951   )
1952 {
1953   UINTN Index;
1954 
1955   for (Index = 0; Index < MaxType; Index++) {
1956     mGlobal->GoVirtualChildEvent[Index] (Event, mGlobal->VariableStore[Index]);
1957     EfiConvertPointer (0, (VOID**) &mGlobal->VariableStore[Index]);
1958     EfiConvertPointer (0, &mGlobal->VariableBase[Index]);
1959   }
1960   EfiConvertPointer (0, (VOID **) &mGlobal->PlatformLangCodes);
1961   EfiConvertPointer (0, (VOID **) &mGlobal->LangCodes);
1962   EfiConvertPointer (0, (VOID **) &mGlobal->PlatformLang);
1963   EfiConvertPointer (0, &mGlobal->Scratch);
1964   EfiConvertPointer (0, (VOID**) &mGlobal);
1965 }
1966