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 - 2014, 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)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
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                            Data pointer
1324 
1325 Returns:
1326 
1327   EFI STATUS
1328 
1329 --*/
1330 {
1331   VARIABLE_POINTER_TRACK  Variable;
1332   UINTN                   VarDataSize;
1333   EFI_STATUS              Status;
1334 
1335   if (VariableName == NULL || VendorGuid == NULL || DataSize == NULL) {
1336     return EFI_INVALID_PARAMETER;
1337   }
1338 
1339   //
1340   // Find existing variable
1341   //
1342   Status = FindVariable (VariableName, VendorGuid, &Variable);
1343 
1344   if (Variable.CurrPtr == NULL || EFI_ERROR (Status)) {
1345     return Status;
1346   }
1347   //
1348   // Get data size
1349   //
1350   VarDataSize = Variable.CurrPtr->DataSize;
1351   if (*DataSize >= VarDataSize) {
1352     if (Data == NULL) {
1353       return EFI_INVALID_PARAMETER;
1354     }
1355     CopyMem (Data, GetVariableDataPtr (Variable.CurrPtr), VarDataSize);
1356 
1357     if (Attributes != NULL) {
1358       *Attributes = Variable.CurrPtr->Attributes;
1359     }
1360 
1361     *DataSize = VarDataSize;
1362 
1363     return EFI_SUCCESS;
1364   } else {
1365     *DataSize = VarDataSize;
1366     return EFI_BUFFER_TOO_SMALL;
1367   }
1368 }
1369 
1370 EFI_STATUS
1371 EFIAPI
GetNextVariableName(IN OUT UINTN * VariableNameSize,IN OUT CHAR16 * VariableName,IN OUT EFI_GUID * VendorGuid)1372 GetNextVariableName (
1373   IN OUT  UINTN             *VariableNameSize,
1374   IN OUT  CHAR16            *VariableName,
1375   IN OUT  EFI_GUID          *VendorGuid
1376   )
1377 /*++
1378 
1379 Routine Description:
1380 
1381   This code Finds the Next available variable
1382 
1383 Arguments:
1384 
1385   VariableNameSize            Size of the variable
1386   VariableName                Pointer to variable name
1387   VendorGuid                  Variable Vendor Guid
1388 
1389 Returns:
1390 
1391   EFI STATUS
1392 
1393 --*/
1394 {
1395   VARIABLE_POINTER_TRACK  Variable;
1396   UINTN                   VarNameSize;
1397   EFI_STATUS              Status;
1398 
1399   if (VariableNameSize == NULL || VariableName == NULL || VendorGuid == NULL) {
1400     return EFI_INVALID_PARAMETER;
1401   }
1402 
1403   Status = FindVariable (VariableName, VendorGuid, &Variable);
1404 
1405   if (Variable.CurrPtr == NULL || EFI_ERROR (Status)) {
1406     return Status;
1407   }
1408 
1409   if (VariableName[0] != 0) {
1410     //
1411     // If variable name is not NULL, get next variable
1412     //
1413     Variable.CurrPtr = GetNextVariablePtr (Variable.CurrPtr);
1414   }
1415 
1416   while (TRUE) {
1417     //
1418     // The order we find variable is: 1). NonVolatile; 2). Volatile
1419     // If both volatile and non-volatile variable store are parsed,
1420     // return not found
1421     //
1422     if (Variable.CurrPtr >= Variable.EndPtr || Variable.CurrPtr == NULL) {
1423       if (Variable.Type == Volatile) {
1424         //
1425         // Since we met the end of Volatile storage, we have parsed all the stores.
1426         //
1427         return EFI_NOT_FOUND;
1428       }
1429 
1430       //
1431       // End of NonVolatile, continue to parse Volatile
1432       //
1433       Variable.Type = Volatile;
1434       Variable.StartPtr = (VARIABLE_HEADER *) ((VARIABLE_STORE_HEADER *) mGlobal->VariableBase[Volatile] + 1);
1435       Variable.EndPtr   = (VARIABLE_HEADER *) GetEndPointer ((VARIABLE_STORE_HEADER *) mGlobal->VariableBase[Volatile]);
1436 
1437       Variable.CurrPtr = Variable.StartPtr;
1438       if (!IsValidVariableHeader (Variable.CurrPtr)) {
1439         continue;
1440       }
1441     }
1442     //
1443     // Variable is found
1444     //
1445     if (IsValidVariableHeader (Variable.CurrPtr) &&
1446         ((Variable.CurrPtr->State == VAR_ADDED) ||
1447          (Variable.CurrPtr->State == (VAR_ADDED & VAR_IN_DELETED_TRANSITION)))) {
1448       if (!EfiAtRuntime () || (Variable.CurrPtr->Attributes & EFI_VARIABLE_RUNTIME_ACCESS)) {
1449         VarNameSize = Variable.CurrPtr->NameSize;
1450         if (VarNameSize <= *VariableNameSize) {
1451           CopyMem (
1452             VariableName,
1453             GET_VARIABLE_NAME_PTR (Variable.CurrPtr),
1454             VarNameSize
1455             );
1456           CopyMem (
1457             VendorGuid,
1458             &Variable.CurrPtr->VendorGuid,
1459             sizeof (EFI_GUID)
1460             );
1461           Status = EFI_SUCCESS;
1462         } else {
1463           Status = EFI_BUFFER_TOO_SMALL;
1464         }
1465 
1466         *VariableNameSize = VarNameSize;
1467         return Status;
1468       }
1469     }
1470 
1471     Variable.CurrPtr = GetNextVariablePtr (Variable.CurrPtr);
1472   }
1473 }
1474 
1475 EFI_STATUS
1476 EFIAPI
SetVariable(IN CHAR16 * VariableName,IN EFI_GUID * VendorGuid,IN UINT32 Attributes,IN UINTN DataSize,IN VOID * Data)1477 SetVariable (
1478   IN CHAR16                  *VariableName,
1479   IN EFI_GUID                *VendorGuid,
1480   IN UINT32                  Attributes,
1481   IN UINTN                   DataSize,
1482   IN VOID                    *Data
1483   )
1484 /*++
1485 
1486 Routine Description:
1487 
1488   This code sets variable in storage blocks (Volatile or Non-Volatile)
1489 
1490 Arguments:
1491 
1492   VariableName                    Name of Variable to be found
1493   VendorGuid                      Variable vendor GUID
1494   Attributes                      Attribute value of the variable found
1495   DataSize                        Size of Data found. If size is less than the
1496                                   data, this value contains the required size.
1497   Data                            Data pointer
1498 
1499 Returns:
1500 
1501   EFI_INVALID_PARAMETER           - Invalid parameter
1502   EFI_SUCCESS                     - Set successfully
1503   EFI_OUT_OF_RESOURCES            - Resource not enough to set variable
1504   EFI_NOT_FOUND                   - Not found
1505   EFI_DEVICE_ERROR                - Variable can not be saved due to hardware failure
1506   EFI_WRITE_PROTECTED             - Variable is read-only
1507 
1508 --*/
1509 {
1510   VARIABLE_POINTER_TRACK  Variable;
1511   EFI_STATUS              Status;
1512 
1513   //
1514   // Check input parameters
1515   //
1516   if (VariableName == NULL || VariableName[0] == 0 || VendorGuid == NULL) {
1517     return EFI_INVALID_PARAMETER;
1518   }
1519 
1520   if (DataSize != 0 && Data == NULL) {
1521     return EFI_INVALID_PARAMETER;
1522   }
1523 
1524   //
1525   // Not support authenticated variable write yet.
1526   //
1527   if ((Attributes & EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS) != 0) {
1528     return EFI_INVALID_PARAMETER;
1529   }
1530 
1531   //
1532   //  Make sure if runtime bit is set, boot service bit is set also
1533   //
1534   if ((Attributes & (EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS)) == EFI_VARIABLE_RUNTIME_ACCESS) {
1535     return EFI_INVALID_PARAMETER;
1536   }
1537 
1538   //
1539   //  The size of the VariableName, including the Unicode Null in bytes plus
1540   //  the DataSize is limited to maximum size of PcdGet32 (PcdMaxHardwareErrorVariableSize)
1541   //  bytes for HwErrRec, and PcdGet32 (PcdMaxVariableSize) bytes for the others.
1542   //
1543   if ((Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == EFI_VARIABLE_HARDWARE_ERROR_RECORD) {
1544     if ((DataSize > PcdGet32(PcdMaxHardwareErrorVariableSize)) ||
1545         (sizeof (VARIABLE_HEADER) + StrSize (VariableName) + DataSize > PcdGet32(PcdMaxHardwareErrorVariableSize))) {
1546       return EFI_INVALID_PARAMETER;
1547     }
1548     //
1549     // According to UEFI spec, HARDWARE_ERROR_RECORD variable name convention should be L"HwErrRecXXXX"
1550     //
1551     if (StrnCmp(VariableName, L"HwErrRec", StrLen(L"HwErrRec")) != 0) {
1552       return EFI_INVALID_PARAMETER;
1553     }
1554   } else {
1555     if ((DataSize > PcdGet32(PcdMaxVariableSize)) ||
1556         (sizeof (VARIABLE_HEADER) + StrSize (VariableName) + DataSize > PcdGet32(PcdMaxVariableSize))) {
1557       return EFI_INVALID_PARAMETER;
1558     }
1559   }
1560 
1561   //
1562   // Check whether the input variable is already existed
1563   //
1564   Status = FindVariable (VariableName, VendorGuid, &Variable);
1565 
1566   //
1567   // Hook the operation of setting PlatformLangCodes/PlatformLang and LangCodes/Lang
1568   //
1569   AutoUpdateLangVariable (VariableName, Data, DataSize);
1570 
1571   Status = UpdateVariable (VariableName, VendorGuid, Data, DataSize, Attributes, &Variable);
1572 
1573   return Status;
1574 }
1575 
1576 EFI_STATUS
1577 EFIAPI
QueryVariableInfo(IN UINT32 Attributes,OUT UINT64 * MaximumVariableStorageSize,OUT UINT64 * RemainingVariableStorageSize,OUT UINT64 * MaximumVariableSize)1578 QueryVariableInfo (
1579   IN  UINT32                 Attributes,
1580   OUT UINT64                 *MaximumVariableStorageSize,
1581   OUT UINT64                 *RemainingVariableStorageSize,
1582   OUT UINT64                 *MaximumVariableSize
1583   )
1584 /*++
1585 
1586 Routine Description:
1587 
1588   This code returns information about the EFI variables.
1589 
1590 Arguments:
1591 
1592   Attributes                      Attributes bitmask to specify the type of variables
1593                                   on which to return information.
1594   MaximumVariableStorageSize      Pointer to the maximum size of the storage space available
1595                                   for the EFI variables associated with the attributes specified.
1596   RemainingVariableStorageSize    Pointer to the remaining size of the storage space available
1597                                   for the EFI variables associated with the attributes specified.
1598   MaximumVariableSize             Pointer to the maximum size of the individual EFI variables
1599                                   associated with the attributes specified.
1600 
1601 Returns:
1602 
1603   EFI STATUS
1604   EFI_INVALID_PARAMETER           - An invalid combination of attribute bits was supplied.
1605   EFI_SUCCESS                     - Query successfully.
1606   EFI_UNSUPPORTED                 - The attribute is not supported on this platform.
1607 
1608 --*/
1609 {
1610   VARIABLE_HEADER        *Variable;
1611   VARIABLE_HEADER        *NextVariable;
1612   UINT64                 VariableSize;
1613   VARIABLE_STORE_HEADER  *VariableStoreHeader;
1614   UINT64                 CommonVariableTotalSize;
1615   UINT64                 HwErrVariableTotalSize;
1616 
1617   CommonVariableTotalSize = 0;
1618   HwErrVariableTotalSize = 0;
1619 
1620   if(MaximumVariableStorageSize == NULL || RemainingVariableStorageSize == NULL || MaximumVariableSize == NULL || Attributes == 0) {
1621     return EFI_INVALID_PARAMETER;
1622   }
1623 
1624   if((Attributes & (EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_HARDWARE_ERROR_RECORD)) == 0) {
1625     //
1626     // Make sure the Attributes combination is supported by the platform.
1627     //
1628     return EFI_UNSUPPORTED;
1629   } else if ((Attributes & (EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS)) == EFI_VARIABLE_RUNTIME_ACCESS) {
1630     //
1631     // Make sure if runtime bit is set, boot service bit is set also.
1632     //
1633     return EFI_INVALID_PARAMETER;
1634   } else if (EfiAtRuntime () && !(Attributes & EFI_VARIABLE_RUNTIME_ACCESS)) {
1635     //
1636     // Make sure RT Attribute is set if we are in Runtime phase.
1637     //
1638     return EFI_INVALID_PARAMETER;
1639   } else if ((Attributes & (EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_HARDWARE_ERROR_RECORD)) == EFI_VARIABLE_HARDWARE_ERROR_RECORD) {
1640     //
1641     // Make sure Hw Attribute is set with NV.
1642     //
1643     return EFI_INVALID_PARAMETER;
1644   } else if ((Attributes & EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS) != 0) {
1645     //
1646     // Not support authentiated variable write yet.
1647     //
1648     return EFI_UNSUPPORTED;
1649   }
1650 
1651   VariableStoreHeader = (VARIABLE_STORE_HEADER *) mGlobal->VariableBase[
1652                                 (Attributes & EFI_VARIABLE_NON_VOLATILE) ? NonVolatile : Volatile
1653                                 ];
1654   //
1655   // Now let's fill *MaximumVariableStorageSize *RemainingVariableStorageSize
1656   // with the storage size (excluding the storage header size).
1657   //
1658   *MaximumVariableStorageSize   = VariableStoreHeader->Size - sizeof (VARIABLE_STORE_HEADER);
1659 
1660   //
1661   // Harware error record variable needs larger size.
1662   //
1663   if ((Attributes & (EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_HARDWARE_ERROR_RECORD)) == (EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_HARDWARE_ERROR_RECORD)) {
1664     *MaximumVariableStorageSize = PcdGet32(PcdHwErrStorageSize);
1665     *MaximumVariableSize = PcdGet32(PcdMaxHardwareErrorVariableSize) - sizeof (VARIABLE_HEADER);
1666   } else {
1667     if ((Attributes & EFI_VARIABLE_NON_VOLATILE) != 0) {
1668       ASSERT (PcdGet32(PcdHwErrStorageSize) < VariableStoreHeader->Size);
1669       *MaximumVariableStorageSize = VariableStoreHeader->Size - sizeof (VARIABLE_STORE_HEADER) - PcdGet32(PcdHwErrStorageSize);
1670     }
1671 
1672     //
1673     // Let *MaximumVariableSize be PcdGet32(PcdMaxVariableSize) with the exception of the variable header size.
1674     //
1675     *MaximumVariableSize = PcdGet32(PcdMaxVariableSize) - sizeof (VARIABLE_HEADER);
1676   }
1677 
1678   //
1679   // Point to the starting address of the variables.
1680   //
1681   Variable = (VARIABLE_HEADER *) (VariableStoreHeader + 1);
1682 
1683   //
1684   // Now walk through the related variable store.
1685   //
1686   while ((Variable < GetEndPointer (VariableStoreHeader)) && IsValidVariableHeader (Variable)) {
1687     NextVariable = GetNextVariablePtr (Variable);
1688     VariableSize = (UINT64) (UINTN) NextVariable - (UINT64) (UINTN) Variable;
1689 
1690     if (EfiAtRuntime ()) {
1691       //
1692       // we don't take the state of the variables in mind
1693       // when calculating RemainingVariableStorageSize,
1694       // since the space occupied by variables not marked with
1695       // VAR_ADDED is not allowed to be reclaimed in Runtime.
1696       //
1697       if ((Variable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == EFI_VARIABLE_HARDWARE_ERROR_RECORD) {
1698         HwErrVariableTotalSize += VariableSize;
1699       } else {
1700         CommonVariableTotalSize += VariableSize;
1701       }
1702     } else {
1703       //
1704       // Only care about Variables with State VAR_ADDED,because
1705       // the space not marked as VAR_ADDED is reclaimable now.
1706       //
1707       if ((Variable->State == VAR_ADDED) || (Variable->State == (VAR_ADDED & VAR_IN_DELETED_TRANSITION))) {
1708         if ((Variable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == EFI_VARIABLE_HARDWARE_ERROR_RECORD) {
1709           HwErrVariableTotalSize += VariableSize;
1710         } else {
1711           CommonVariableTotalSize += VariableSize;
1712         }
1713       }
1714     }
1715 
1716     //
1717     // Go to the next one
1718     //
1719     Variable = NextVariable;
1720   }
1721 
1722   if ((Attributes  & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == EFI_VARIABLE_HARDWARE_ERROR_RECORD){
1723     *RemainingVariableStorageSize = *MaximumVariableStorageSize - HwErrVariableTotalSize;
1724   } else {
1725     *RemainingVariableStorageSize = *MaximumVariableStorageSize - CommonVariableTotalSize;
1726   }
1727 
1728   return EFI_SUCCESS;
1729 }
1730 
1731 EFI_STATUS
1732 EFIAPI
VariableServiceInitialize(IN EFI_HANDLE ImageHandle,IN EFI_SYSTEM_TABLE * SystemTable)1733 VariableServiceInitialize (
1734   IN EFI_HANDLE         ImageHandle,
1735   IN EFI_SYSTEM_TABLE   *SystemTable
1736   )
1737 /*++
1738 
1739 Routine Description:
1740   This function does initialization for variable services
1741 
1742 Arguments:
1743 
1744   ImageHandle   - The firmware allocated handle for the EFI image.
1745   SystemTable   - A pointer to the EFI System Table.
1746 
1747 Returns:
1748 
1749   Status code.
1750 
1751   EFI_NOT_FOUND     - Variable store area not found.
1752   EFI_SUCCESS       - Variable services successfully initialized.
1753 
1754 --*/
1755 {
1756   EFI_STATUS                      Status;
1757   EFI_HANDLE                      NewHandle;
1758   VS_DEV                          *Dev;
1759   EFI_PEI_HOB_POINTERS            GuidHob;
1760   VARIABLE_HEADER                 *Variable;
1761   VARIABLE_HEADER                 *NextVariable;
1762   VARIABLE_STORE_HEADER           *VariableStoreHeader;
1763   EFI_FLASH_MAP_FS_ENTRY_DATA     *FlashMapEntryData;
1764   EFI_FLASH_SUBAREA_ENTRY         VariableStoreEntry;
1765   UINT64                          BaseAddress;
1766   UINT64                          Length;
1767   EFI_GCD_MEMORY_SPACE_DESCRIPTOR GcdDescriptor;
1768 
1769   Status = gBS->AllocatePool (
1770                   EfiRuntimeServicesData,
1771                   (UINTN) sizeof (VARIABLE_GLOBAL),
1772                   (VOID**) &mGlobal
1773                   );
1774   if (EFI_ERROR (Status)) {
1775     return Status;
1776   }
1777 
1778   ZeroMem (mGlobal, (UINTN) sizeof (VARIABLE_GLOBAL));
1779 
1780   GuidHob.Raw = GetHobList ();
1781   FlashMapEntryData = NULL;
1782   while ((GuidHob.Raw = GetNextGuidHob (&gEfiFlashMapHobGuid, GuidHob.Raw)) != NULL) {
1783     FlashMapEntryData = (EFI_FLASH_MAP_FS_ENTRY_DATA *) GET_GUID_HOB_DATA (GuidHob.Guid);
1784     if (FlashMapEntryData->AreaType == EFI_FLASH_AREA_EFI_VARIABLES) {
1785       break;
1786     }
1787     GuidHob.Raw = GET_NEXT_HOB (GuidHob);
1788   }
1789 
1790   if (FlashMapEntryData == NULL) {
1791     DEBUG ((EFI_D_ERROR, "FSVariable: Could not find flash area for variable!\n"));
1792     Status = EFI_NOT_FOUND;
1793     return Status;
1794   }
1795 
1796   CopyMem(
1797     (VOID*)&VariableStoreEntry,
1798     (VOID*)&FlashMapEntryData->Entries[0],
1799     sizeof(EFI_FLASH_SUBAREA_ENTRY)
1800     );
1801 
1802   //
1803   // Mark the variable storage region of the FLASH as RUNTIME
1804   //
1805   BaseAddress = VariableStoreEntry.Base & (~EFI_PAGE_MASK);
1806   Length      = VariableStoreEntry.Length + (VariableStoreEntry.Base - BaseAddress);
1807   Length      = (Length + EFI_PAGE_SIZE - 1) & (~EFI_PAGE_MASK);
1808   Status      = gDS->GetMemorySpaceDescriptor (BaseAddress, &GcdDescriptor);
1809   if (EFI_ERROR (Status)) {
1810     Status = EFI_UNSUPPORTED;
1811     return Status;
1812   }
1813   Status = gDS->SetMemorySpaceAttributes (
1814                   BaseAddress,
1815                   Length,
1816                   GcdDescriptor.Attributes | EFI_MEMORY_RUNTIME
1817                   );
1818   if (EFI_ERROR (Status)) {
1819     Status = EFI_UNSUPPORTED;
1820     return Status;
1821   }
1822 
1823   Status = FileStorageConstructor (
1824              &mGlobal->VariableStore[NonVolatile],
1825              &mGlobal->GoVirtualChildEvent[NonVolatile],
1826              VariableStoreEntry.Base,
1827              (UINT32) VariableStoreEntry.Length,
1828              FlashMapEntryData->VolumeId,
1829              FlashMapEntryData->FilePath
1830              );
1831   ASSERT_EFI_ERROR (Status);
1832 
1833   //
1834   // Volatile Storage
1835   //
1836   Status = MemStorageConstructor (
1837              &mGlobal->VariableStore[Volatile],
1838              &mGlobal->GoVirtualChildEvent[Volatile],
1839              VOLATILE_VARIABLE_STORE_SIZE
1840              );
1841   ASSERT_EFI_ERROR (Status);
1842 
1843   //
1844   // Scratch
1845   //
1846   Status = gBS->AllocatePool (
1847                   EfiRuntimeServicesData,
1848                   VARIABLE_SCRATCH_SIZE,
1849                   &mGlobal->Scratch
1850                   );
1851   ASSERT_EFI_ERROR (Status);
1852 
1853   //
1854   // 1. NV Storage
1855   //
1856   Dev = DEV_FROM_THIS (mGlobal->VariableStore[NonVolatile]);
1857   VariableStoreHeader = (VARIABLE_STORE_HEADER *) VAR_DATA_PTR (Dev);
1858   if (GetVariableStoreStatus (VariableStoreHeader) == EfiValid) {
1859     if (~VariableStoreHeader->Size == 0) {
1860       VariableStoreHeader->Size = (UINT32) VariableStoreEntry.Length;
1861     }
1862   }
1863   //
1864   // Calculate LastVariableOffset
1865   //
1866   Variable = (VARIABLE_HEADER *) (VariableStoreHeader + 1);
1867   while (IsValidVariableHeader (Variable)) {
1868     UINTN VariableSize = 0;
1869     NextVariable = GetNextVariablePtr (Variable);
1870     VariableSize = NextVariable - Variable;
1871     if ((NextVariable->Attributes & (EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_HARDWARE_ERROR_RECORD)) == (EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_HARDWARE_ERROR_RECORD)) {
1872       mGlobal->HwErrVariableTotalSize += HEADER_ALIGN (VariableSize);
1873     } else {
1874       mGlobal->CommonVariableTotalSize += HEADER_ALIGN (VariableSize);
1875     }
1876     Variable = NextVariable;
1877   }
1878 
1879   mGlobal->LastVariableOffset[NonVolatile] = (UINTN) Variable - (UINTN) VariableStoreHeader;
1880   mGlobal->VariableBase[NonVolatile]       = VariableStoreHeader;
1881 
1882   //
1883   // Reclaim if remaining space is too small
1884   //
1885   if ((VariableStoreHeader->Size - mGlobal->LastVariableOffset[NonVolatile]) < VARIABLE_RECLAIM_THRESHOLD) {
1886     Status = Reclaim (NonVolatile, NULL);
1887     if (EFI_ERROR (Status)) {
1888       //
1889       // Reclaim error
1890       // we cannot restore to original state
1891       //
1892       DEBUG ((EFI_D_ERROR, "FSVariable: Reclaim error (fatal error) - %r\n", Status));
1893       ASSERT_EFI_ERROR (Status);
1894     }
1895   }
1896 
1897   //
1898   // 2. Volatile Storage
1899   //
1900   Dev = DEV_FROM_THIS (mGlobal->VariableStore[Volatile]);
1901   VariableStoreHeader = (VARIABLE_STORE_HEADER *) VAR_DATA_PTR (Dev);
1902   mGlobal->VariableBase[Volatile] = VAR_DATA_PTR (Dev);
1903   mGlobal->LastVariableOffset[Volatile] = sizeof (VARIABLE_STORE_HEADER);
1904   //
1905   // init store_header & body in memory.
1906   //
1907   mGlobal->VariableStore[Volatile]->Erase (mGlobal->VariableStore[Volatile]);
1908   mGlobal->VariableStore[Volatile]->Write (
1909                                    mGlobal->VariableStore[Volatile],
1910                                    0,
1911                                    sizeof (VARIABLE_STORE_HEADER),
1912                                    &mStoreHeaderTemplate
1913                                    );
1914 
1915 
1916   SystemTable->RuntimeServices->GetVariable         = DuetGetVariable;
1917   SystemTable->RuntimeServices->GetNextVariableName = GetNextVariableName;
1918   SystemTable->RuntimeServices->SetVariable         = SetVariable;
1919 
1920   SystemTable->RuntimeServices->QueryVariableInfo   = QueryVariableInfo;
1921 
1922   //
1923   // Now install the Variable Runtime Architectural Protocol on a new handle
1924   //
1925   NewHandle = NULL;
1926   Status = gBS->InstallMultipleProtocolInterfaces (
1927                   &NewHandle,
1928                   &gEfiVariableArchProtocolGuid,
1929                   NULL,
1930                   &gEfiVariableWriteArchProtocolGuid,
1931                   NULL,
1932                   NULL
1933                   );
1934   ASSERT_EFI_ERROR (Status);
1935 
1936   return Status;
1937 }
1938 
1939 
1940 
1941 VOID
1942 EFIAPI
OnVirtualAddressChangeFsv(IN EFI_EVENT Event,IN VOID * Context)1943 OnVirtualAddressChangeFsv (
1944   IN EFI_EVENT        Event,
1945   IN VOID             *Context
1946   )
1947 {
1948   UINTN Index;
1949 
1950   for (Index = 0; Index < MaxType; Index++) {
1951     mGlobal->GoVirtualChildEvent[Index] (Event, mGlobal->VariableStore[Index]);
1952     EfiConvertPointer (0, (VOID**) &mGlobal->VariableStore[Index]);
1953     EfiConvertPointer (0, &mGlobal->VariableBase[Index]);
1954   }
1955   EfiConvertPointer (0, (VOID **) &mGlobal->PlatformLangCodes);
1956   EfiConvertPointer (0, (VOID **) &mGlobal->LangCodes);
1957   EfiConvertPointer (0, (VOID **) &mGlobal->PlatformLang);
1958   EfiConvertPointer (0, &mGlobal->Scratch);
1959   EfiConvertPointer (0, (VOID**) &mGlobal);
1960 }
1961