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