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 - 2016, 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   if (VariableName[0] == 0) {
1187     return EFI_NOT_FOUND;
1188   }
1189 
1190   AcquireLockOnlyAtBootTime(&Global->VariableServicesLock);
1191 
1192   //
1193   // Find existing variable
1194   //
1195   Status = FindVariable (VariableName, VendorGuid, &Variable, Global);
1196 
1197   if (Variable.CurrPtr == NULL || EFI_ERROR (Status)) {
1198     goto Done;
1199   }
1200   //
1201   // Get data size
1202   //
1203   VarDataSize = Variable.CurrPtr->DataSize;
1204   if (*DataSize >= VarDataSize) {
1205     if (Data == NULL) {
1206       Status = EFI_INVALID_PARAMETER;
1207       goto Done;
1208     }
1209     VariableDataPtr = GetVariableDataPtr (Variable.CurrPtr);
1210     ASSERT (VariableDataPtr != NULL);
1211 
1212     CopyMem (Data, VariableDataPtr, VarDataSize);
1213     if (Attributes != NULL) {
1214       *Attributes = Variable.CurrPtr->Attributes;
1215     }
1216 
1217     *DataSize = VarDataSize;
1218     UpdateVariableInfo (VariableName, VendorGuid, Variable.Volatile, TRUE, FALSE, FALSE, FALSE);
1219     Status = EFI_SUCCESS;
1220     goto Done;
1221   } else {
1222     *DataSize = VarDataSize;
1223     Status = EFI_BUFFER_TOO_SMALL;
1224     goto Done;
1225   }
1226 
1227 Done:
1228   ReleaseLockOnlyAtBootTime (&Global->VariableServicesLock);
1229   return Status;
1230 }
1231 
1232 /**
1233 
1234   This code Finds the Next available variable.
1235 
1236   @param  VariableNameSize       Size of the variable.
1237   @param  VariableName           On input, supplies the last VariableName that was returned by GetNextVariableName().
1238                                  On output, returns the Null-terminated Unicode string of the current variable.
1239   @param  VendorGuid             On input, supplies the last VendorGuid that was returned by GetNextVariableName().
1240                                  On output, returns the VendorGuid of the current variable.
1241   @param  Global                 Pointer to VARIABLE_GLOBAL structure.
1242 
1243   @retval EFI_SUCCESS            The function completed successfully.
1244   @retval EFI_NOT_FOUND          The next variable was not found.
1245   @retval EFI_BUFFER_TOO_SMALL   VariableNameSize is too small for the result.
1246                                  VariableNameSize has been updated with the size needed to complete the request.
1247   @retval EFI_INVALID_PARAMETER  VariableNameSize or VariableName or VendorGuid is NULL.
1248 
1249 **/
1250 EFI_STATUS
1251 EFIAPI
EmuGetNextVariableName(IN OUT UINTN * VariableNameSize,IN OUT CHAR16 * VariableName,IN OUT EFI_GUID * VendorGuid,IN VARIABLE_GLOBAL * Global)1252 EmuGetNextVariableName (
1253   IN OUT  UINTN             *VariableNameSize,
1254   IN OUT  CHAR16            *VariableName,
1255   IN OUT  EFI_GUID          *VendorGuid,
1256   IN      VARIABLE_GLOBAL   *Global
1257   )
1258 {
1259   VARIABLE_POINTER_TRACK  Variable;
1260   UINTN                   VarNameSize;
1261   EFI_STATUS              Status;
1262 
1263   if (VariableNameSize == NULL || VariableName == NULL || VendorGuid == NULL) {
1264     return EFI_INVALID_PARAMETER;
1265   }
1266 
1267   AcquireLockOnlyAtBootTime(&Global->VariableServicesLock);
1268 
1269   Status = FindVariable (VariableName, VendorGuid, &Variable, Global);
1270 
1271   if (Variable.CurrPtr == NULL || EFI_ERROR (Status)) {
1272     goto Done;
1273   }
1274 
1275   while (TRUE) {
1276     if (VariableName[0] != 0) {
1277       //
1278       // If variable name is not NULL, get next variable
1279       //
1280       Variable.CurrPtr = GetNextVariablePtr (Variable.CurrPtr);
1281     }
1282     //
1283     // If both volatile and non-volatile variable store are parsed,
1284     // return not found
1285     //
1286     if (Variable.CurrPtr >= Variable.EndPtr || Variable.CurrPtr == NULL) {
1287       Variable.Volatile = (BOOLEAN) (Variable.Volatile ^ ((BOOLEAN) 0x1));
1288       if (Variable.Volatile) {
1289         Variable.StartPtr = (VARIABLE_HEADER *) HEADER_ALIGN ((UINTN) (Global->VolatileVariableBase + sizeof (VARIABLE_STORE_HEADER)));
1290         Variable.EndPtr = (VARIABLE_HEADER *) GetEndPointer ((VARIABLE_STORE_HEADER *) ((UINTN) Global->VolatileVariableBase));
1291       } else {
1292         Status = EFI_NOT_FOUND;
1293         goto Done;
1294       }
1295 
1296       Variable.CurrPtr = Variable.StartPtr;
1297       if (Variable.CurrPtr->StartId != VARIABLE_DATA) {
1298         continue;
1299       }
1300     }
1301     //
1302     // Variable is found
1303     //
1304     if (Variable.CurrPtr->StartId == VARIABLE_DATA && Variable.CurrPtr->State == VAR_ADDED) {
1305       if (!(EfiAtRuntime () && ((Variable.CurrPtr->Attributes & EFI_VARIABLE_RUNTIME_ACCESS) == 0))) {
1306         VarNameSize = Variable.CurrPtr->NameSize;
1307         if (VarNameSize <= *VariableNameSize) {
1308           CopyMem (
1309             VariableName,
1310             GET_VARIABLE_NAME_PTR (Variable.CurrPtr),
1311             VarNameSize
1312             );
1313           CopyMem (
1314             VendorGuid,
1315             &Variable.CurrPtr->VendorGuid,
1316             sizeof (EFI_GUID)
1317             );
1318           Status = EFI_SUCCESS;
1319         } else {
1320           Status = EFI_BUFFER_TOO_SMALL;
1321         }
1322 
1323         *VariableNameSize = VarNameSize;
1324         goto Done;
1325       }
1326     }
1327   }
1328 
1329 Done:
1330   ReleaseLockOnlyAtBootTime (&Global->VariableServicesLock);
1331   return Status;
1332 
1333 }
1334 
1335 /**
1336 
1337   This code sets variable in storage blocks (Volatile or Non-Volatile).
1338 
1339   @param  VariableName           A Null-terminated Unicode string that is the name of the vendor's
1340                                  variable.  Each VariableName is unique for each
1341                                  VendorGuid.  VariableName must contain 1 or more
1342                                  Unicode characters.  If VariableName is an empty Unicode
1343                                  string, then EFI_INVALID_PARAMETER is returned.
1344   @param  VendorGuid             A unique identifier for the vendor
1345   @param  Attributes             Attributes bitmask to set for the variable
1346   @param  DataSize               The size in bytes of the Data buffer.  A size of zero causes the
1347                                  variable to be deleted.
1348   @param  Data                   The contents for the variable
1349   @param  Global                 Pointer to VARIABLE_GLOBAL structure
1350   @param  VolatileOffset         The offset of last volatile variable
1351   @param  NonVolatileOffset      The offset of last non-volatile variable
1352 
1353   @retval EFI_SUCCESS            The firmware has successfully stored the variable and its data as
1354                                  defined by the Attributes.
1355   @retval EFI_INVALID_PARAMETER  An invalid combination of attribute bits was supplied, or the
1356                                  DataSize exceeds the maximum allowed, or VariableName is an empty
1357                                  Unicode string, or VendorGuid is NULL.
1358   @retval EFI_OUT_OF_RESOURCES   Not enough storage is available to hold the variable and its data.
1359   @retval EFI_DEVICE_ERROR       The variable could not be saved due to a hardware failure.
1360   @retval EFI_WRITE_PROTECTED    The variable in question is read-only or cannot be deleted.
1361   @retval EFI_NOT_FOUND          The variable trying to be updated or deleted was not found.
1362 
1363 **/
1364 EFI_STATUS
1365 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)1366 EmuSetVariable (
1367   IN CHAR16                  *VariableName,
1368   IN EFI_GUID                *VendorGuid,
1369   IN UINT32                  Attributes,
1370   IN UINTN                   DataSize,
1371   IN VOID                    *Data,
1372   IN VARIABLE_GLOBAL         *Global,
1373   IN UINTN                   *VolatileOffset,
1374   IN UINTN                   *NonVolatileOffset
1375   )
1376 {
1377   VARIABLE_POINTER_TRACK  Variable;
1378   EFI_STATUS              Status;
1379 
1380   //
1381   // Check input parameters
1382   //
1383   if (VariableName == NULL || VariableName[0] == 0 || VendorGuid == NULL) {
1384     return EFI_INVALID_PARAMETER;
1385   }
1386 
1387   if (DataSize != 0 && Data == NULL) {
1388     return EFI_INVALID_PARAMETER;
1389   }
1390 
1391   //
1392   // Not support authenticated variable write yet.
1393   //
1394   if ((Attributes & EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS) != 0) {
1395     return EFI_INVALID_PARAMETER;
1396   }
1397 
1398   //
1399   //  Make sure if runtime bit is set, boot service bit is set also
1400   //
1401   if ((Attributes & (EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS)) == EFI_VARIABLE_RUNTIME_ACCESS) {
1402     return EFI_INVALID_PARAMETER;
1403   }
1404 
1405 
1406   if ((UINTN)(~0) - DataSize < StrSize(VariableName)){
1407     //
1408     // Prevent whole variable size overflow
1409     //
1410     return EFI_INVALID_PARAMETER;
1411   }
1412 
1413   //
1414   //  The size of the VariableName, including the Unicode Null in bytes plus
1415   //  the DataSize is limited to maximum size of PcdGet32 (PcdMaxHardwareErrorVariableSize)
1416   //  bytes for HwErrRec, and PcdGet32 (PcdMaxVariableSize) bytes for the others.
1417   //
1418   if ((Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == EFI_VARIABLE_HARDWARE_ERROR_RECORD) {
1419     if (StrSize (VariableName) + DataSize > PcdGet32 (PcdMaxHardwareErrorVariableSize) - sizeof (VARIABLE_HEADER)) {
1420       return EFI_INVALID_PARAMETER;
1421     }
1422     //
1423     // According to UEFI spec, HARDWARE_ERROR_RECORD variable name convention should be L"HwErrRecXXXX"
1424     //
1425     if (StrnCmp(VariableName, L"HwErrRec", StrLen(L"HwErrRec")) != 0) {
1426       return EFI_INVALID_PARAMETER;
1427     }
1428   } else {
1429   //
1430   //  The size of the VariableName, including the Unicode Null in bytes plus
1431   //  the DataSize is limited to maximum size of PcdGet32 (PcdMaxVariableSize) bytes.
1432   //
1433     if (StrSize (VariableName) + DataSize > PcdGet32 (PcdMaxVariableSize) - sizeof (VARIABLE_HEADER)) {
1434       return EFI_INVALID_PARAMETER;
1435     }
1436   }
1437 
1438   AcquireLockOnlyAtBootTime(&Global->VariableServicesLock);
1439 
1440   //
1441   // Check whether the input variable is already existed
1442   //
1443 
1444   Status = FindVariable (VariableName, VendorGuid, &Variable, Global);
1445 
1446   //
1447   // Hook the operation of setting PlatformLangCodes/PlatformLang and LangCodes/Lang
1448   //
1449   AutoUpdateLangVariable (VariableName, Data, DataSize);
1450 
1451   Status = UpdateVariable (VariableName, VendorGuid, Data, DataSize, Attributes, &Variable);
1452 
1453   ReleaseLockOnlyAtBootTime (&Global->VariableServicesLock);
1454   return Status;
1455 }
1456 
1457 /**
1458 
1459   This code returns information about the EFI variables.
1460 
1461   @param  Attributes                   Attributes bitmask to specify the type of variables
1462                                        on which to return information.
1463   @param  MaximumVariableStorageSize   On output the maximum size of the storage space available for
1464                                        the EFI variables associated with the attributes specified.
1465   @param  RemainingVariableStorageSize Returns the remaining size of the storage space available for EFI
1466                                        variables associated with the attributes specified.
1467   @param  MaximumVariableSize          Returns the maximum size of an individual EFI variable
1468                                        associated with the attributes specified.
1469   @param  Global                       Pointer to VARIABLE_GLOBAL structure.
1470 
1471   @retval EFI_SUCCESS                  Valid answer returned.
1472   @retval EFI_INVALID_PARAMETER        An invalid combination of attribute bits was supplied
1473   @retval EFI_UNSUPPORTED              The attribute is not supported on this platform, and the
1474                                        MaximumVariableStorageSize, RemainingVariableStorageSize,
1475                                        MaximumVariableSize are undefined.
1476 
1477 **/
1478 EFI_STATUS
1479 EFIAPI
EmuQueryVariableInfo(IN UINT32 Attributes,OUT UINT64 * MaximumVariableStorageSize,OUT UINT64 * RemainingVariableStorageSize,OUT UINT64 * MaximumVariableSize,IN VARIABLE_GLOBAL * Global)1480 EmuQueryVariableInfo (
1481   IN  UINT32                 Attributes,
1482   OUT UINT64                 *MaximumVariableStorageSize,
1483   OUT UINT64                 *RemainingVariableStorageSize,
1484   OUT UINT64                 *MaximumVariableSize,
1485   IN  VARIABLE_GLOBAL        *Global
1486   )
1487 {
1488   VARIABLE_HEADER        *Variable;
1489   VARIABLE_HEADER        *NextVariable;
1490   UINT64                 VariableSize;
1491   VARIABLE_STORE_HEADER  *VariableStoreHeader;
1492   UINT64                 CommonVariableTotalSize;
1493   UINT64                 HwErrVariableTotalSize;
1494 
1495   CommonVariableTotalSize = 0;
1496   HwErrVariableTotalSize = 0;
1497 
1498   if(MaximumVariableStorageSize == NULL || RemainingVariableStorageSize == NULL || MaximumVariableSize == NULL || Attributes == 0) {
1499     return EFI_INVALID_PARAMETER;
1500   }
1501 
1502   if((Attributes & (EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_HARDWARE_ERROR_RECORD)) == 0) {
1503     //
1504     // Make sure the Attributes combination is supported by the platform.
1505     //
1506     return EFI_UNSUPPORTED;
1507   } else if ((Attributes & (EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS)) == EFI_VARIABLE_RUNTIME_ACCESS) {
1508     //
1509     // Make sure if runtime bit is set, boot service bit is set also.
1510     //
1511     return EFI_INVALID_PARAMETER;
1512   } else if (EfiAtRuntime () && ((Attributes & EFI_VARIABLE_RUNTIME_ACCESS) == 0)) {
1513     //
1514     //   Make sure RT Attribute is set if we are in Runtime phase.
1515     //
1516     return EFI_INVALID_PARAMETER;
1517   } else if ((Attributes & (EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_HARDWARE_ERROR_RECORD)) == EFI_VARIABLE_HARDWARE_ERROR_RECORD) {
1518     //
1519     // Make sure Hw Attribute is set with NV.
1520     //
1521     return EFI_INVALID_PARAMETER;
1522   } else if ((Attributes & EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS) != 0) {
1523     //
1524     // Not support authentiated variable write yet.
1525     //
1526     return EFI_UNSUPPORTED;
1527   }
1528 
1529   AcquireLockOnlyAtBootTime(&Global->VariableServicesLock);
1530 
1531   if((Attributes & EFI_VARIABLE_NON_VOLATILE) == 0) {
1532     //
1533     // Query is Volatile related.
1534     //
1535     VariableStoreHeader = (VARIABLE_STORE_HEADER *) ((UINTN) Global->VolatileVariableBase);
1536   } else {
1537     //
1538     // Query is Non-Volatile related.
1539     //
1540     VariableStoreHeader = (VARIABLE_STORE_HEADER *) ((UINTN) Global->NonVolatileVariableBase);
1541   }
1542 
1543   //
1544   // Now let's fill *MaximumVariableStorageSize *RemainingVariableStorageSize
1545   // with the storage size (excluding the storage header size)
1546   //
1547   *MaximumVariableStorageSize   = VariableStoreHeader->Size - sizeof (VARIABLE_STORE_HEADER);
1548 
1549   //
1550   // Harware error record variable needs larger size.
1551   //
1552   if ((Attributes & (EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_HARDWARE_ERROR_RECORD)) == (EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_HARDWARE_ERROR_RECORD)) {
1553     *MaximumVariableStorageSize = PcdGet32 (PcdHwErrStorageSize);
1554     *MaximumVariableSize = PcdGet32 (PcdMaxHardwareErrorVariableSize) - sizeof (VARIABLE_HEADER);
1555   } else {
1556     if ((Attributes & EFI_VARIABLE_NON_VOLATILE) != 0) {
1557       ASSERT (PcdGet32 (PcdHwErrStorageSize) < VariableStoreHeader->Size);
1558       *MaximumVariableStorageSize = VariableStoreHeader->Size - sizeof (VARIABLE_STORE_HEADER) - PcdGet32 (PcdHwErrStorageSize);
1559     }
1560 
1561     //
1562     // Let *MaximumVariableSize be PcdGet32 (PcdMaxVariableSize) with the exception of the variable header size.
1563     //
1564     *MaximumVariableSize = PcdGet32 (PcdMaxVariableSize) - sizeof (VARIABLE_HEADER);
1565   }
1566 
1567   //
1568   // Point to the starting address of the variables.
1569   //
1570   Variable = (VARIABLE_HEADER *) HEADER_ALIGN (VariableStoreHeader + 1);
1571 
1572   //
1573   // Now walk through the related variable store.
1574   //
1575   while (Variable < GetEndPointer (VariableStoreHeader)) {
1576     NextVariable = GetNextVariablePtr(Variable);
1577     if (NextVariable == NULL) {
1578       break;
1579     }
1580     VariableSize = (UINT64) (UINTN) NextVariable - (UINT64) (UINTN) Variable;
1581 
1582     if ((Variable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == EFI_VARIABLE_HARDWARE_ERROR_RECORD) {
1583       HwErrVariableTotalSize += VariableSize;
1584     } else {
1585       CommonVariableTotalSize += VariableSize;
1586     }
1587 
1588     //
1589     // Go to the next one.
1590     //
1591     Variable = NextVariable;
1592   }
1593 
1594   if ((Attributes  & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == EFI_VARIABLE_HARDWARE_ERROR_RECORD){
1595     *RemainingVariableStorageSize = *MaximumVariableStorageSize - HwErrVariableTotalSize;
1596   } else {
1597     *RemainingVariableStorageSize = *MaximumVariableStorageSize - CommonVariableTotalSize;
1598   }
1599 
1600   if (*RemainingVariableStorageSize < sizeof (VARIABLE_HEADER)) {
1601     *MaximumVariableSize = 0;
1602   } else if ((*RemainingVariableStorageSize - sizeof (VARIABLE_HEADER)) < *MaximumVariableSize) {
1603     *MaximumVariableSize = *RemainingVariableStorageSize - sizeof (VARIABLE_HEADER);
1604   }
1605 
1606   ReleaseLockOnlyAtBootTime (&Global->VariableServicesLock);
1607   return EFI_SUCCESS;
1608 }
1609 
1610 /**
1611   Initializes variable store area.
1612 
1613   This function allocates memory space for variable store area and initializes its attributes.
1614 
1615   @param  VolatileStore  Indicates if the variable store is volatile.
1616 
1617 **/
1618 EFI_STATUS
InitializeVariableStore(IN BOOLEAN VolatileStore)1619 InitializeVariableStore (
1620   IN  BOOLEAN               VolatileStore
1621   )
1622 {
1623   EFI_STATUS            Status;
1624   VARIABLE_STORE_HEADER *VariableStore;
1625   BOOLEAN               FullyInitializeStore;
1626   EFI_PHYSICAL_ADDRESS  *VariableBase;
1627   UINTN                 *LastVariableOffset;
1628   VARIABLE_STORE_HEADER *VariableStoreHeader;
1629   VARIABLE_HEADER       *Variable;
1630   VOID                  *VariableData;
1631   EFI_HOB_GUID_TYPE     *GuidHob;
1632 
1633   FullyInitializeStore = TRUE;
1634 
1635   if (VolatileStore) {
1636     VariableBase = &mVariableModuleGlobal->VariableGlobal[Physical].VolatileVariableBase;
1637     LastVariableOffset = &mVariableModuleGlobal->VolatileLastVariableOffset;
1638   } else {
1639     VariableBase = &mVariableModuleGlobal->VariableGlobal[Physical].NonVolatileVariableBase;
1640     LastVariableOffset = &mVariableModuleGlobal->NonVolatileLastVariableOffset;
1641   }
1642 
1643   //
1644   // Note that in EdkII variable driver implementation, Hardware Error Record type variable
1645   // is stored with common variable in the same NV region. So the platform integrator should
1646   // ensure that the value of PcdHwErrStorageSize is less than or equal to the value of
1647   // PcdVariableStoreSize.
1648   //
1649   ASSERT (PcdGet32 (PcdHwErrStorageSize) <= PcdGet32 (PcdVariableStoreSize));
1650 
1651   //
1652   // Allocate memory for variable store.
1653   //
1654   if (VolatileStore || (PcdGet64 (PcdEmuVariableNvStoreReserved) == 0)) {
1655     VariableStore = (VARIABLE_STORE_HEADER *) AllocateRuntimePool (PcdGet32 (PcdVariableStoreSize));
1656   } else {
1657     //
1658     // A memory location has been reserved for the NV variable store.  Certain
1659     // platforms may be able to preserve a memory range across system resets,
1660     // thereby providing better NV variable emulation.
1661     //
1662     VariableStore =
1663       (VARIABLE_STORE_HEADER *)(VOID*)(UINTN)
1664         PcdGet64 (PcdEmuVariableNvStoreReserved);
1665     if (
1666          (VariableStore->Size == PcdGet32 (PcdVariableStoreSize)) &&
1667          (VariableStore->Format == VARIABLE_STORE_FORMATTED) &&
1668          (VariableStore->State == VARIABLE_STORE_HEALTHY)
1669        ) {
1670       DEBUG((
1671         EFI_D_INFO,
1672         "Variable Store reserved at %p appears to be valid\n",
1673         VariableStore
1674         ));
1675       FullyInitializeStore = FALSE;
1676     }
1677   }
1678 
1679   if (NULL == VariableStore) {
1680     return EFI_OUT_OF_RESOURCES;
1681   }
1682 
1683   if (FullyInitializeStore) {
1684     SetMem (VariableStore, PcdGet32 (PcdVariableStoreSize), 0xff);
1685   }
1686 
1687   //
1688   // Variable Specific Data
1689   //
1690   *VariableBase             = (EFI_PHYSICAL_ADDRESS) (UINTN) VariableStore;
1691   InitializeLocationForLastVariableOffset (VariableStore, LastVariableOffset);
1692 
1693   CopyGuid (&VariableStore->Signature, &gEfiVariableGuid);
1694   VariableStore->Size       = PcdGet32 (PcdVariableStoreSize);
1695   VariableStore->Format     = VARIABLE_STORE_FORMATTED;
1696   VariableStore->State      = VARIABLE_STORE_HEALTHY;
1697   VariableStore->Reserved   = 0;
1698   VariableStore->Reserved1  = 0;
1699 
1700   if (!VolatileStore) {
1701     //
1702     // Get HOB variable store.
1703     //
1704     GuidHob = GetFirstGuidHob (&gEfiVariableGuid);
1705     if (GuidHob != NULL) {
1706       VariableStoreHeader = (VARIABLE_STORE_HEADER *) GET_GUID_HOB_DATA (GuidHob);
1707       if (CompareGuid (&VariableStoreHeader->Signature, &gEfiVariableGuid) &&
1708           (VariableStoreHeader->Format == VARIABLE_STORE_FORMATTED) &&
1709           (VariableStoreHeader->State == VARIABLE_STORE_HEALTHY)
1710          ) {
1711         DEBUG ((EFI_D_INFO, "HOB Variable Store appears to be valid.\n"));
1712         //
1713         // Flush the HOB variable to Emulation Variable storage.
1714         //
1715         for ( Variable = (VARIABLE_HEADER *) HEADER_ALIGN (VariableStoreHeader + 1)
1716             ; (Variable < GetEndPointer (VariableStoreHeader) && (Variable != NULL))
1717             ; Variable = GetNextVariablePtr (Variable)
1718             ) {
1719           ASSERT (Variable->State == VAR_ADDED);
1720           ASSERT ((Variable->Attributes & EFI_VARIABLE_NON_VOLATILE) != 0);
1721           VariableData = GetVariableDataPtr (Variable);
1722           Status = EmuSetVariable (
1723                      GET_VARIABLE_NAME_PTR (Variable),
1724                      &Variable->VendorGuid,
1725                      Variable->Attributes,
1726                      Variable->DataSize,
1727                      VariableData,
1728                      &mVariableModuleGlobal->VariableGlobal[Physical],
1729                      &mVariableModuleGlobal->VolatileLastVariableOffset,
1730                      &mVariableModuleGlobal->NonVolatileLastVariableOffset
1731                      );
1732           ASSERT_EFI_ERROR (Status);
1733         }
1734       }
1735     }
1736   }
1737 
1738   return EFI_SUCCESS;
1739 }
1740 
1741 /**
1742   Initializes variable store area for non-volatile and volatile variable.
1743 
1744   This function allocates and initializes memory space for global context of ESAL
1745   variable service and variable store area for non-volatile and volatile variable.
1746 
1747   @param  ImageHandle           The Image handle of this driver.
1748   @param  SystemTable           The pointer of EFI_SYSTEM_TABLE.
1749 
1750   @retval EFI_SUCCESS           Function successfully executed.
1751   @retval EFI_OUT_OF_RESOURCES  Fail to allocate enough memory resource.
1752 
1753 **/
1754 EFI_STATUS
1755 EFIAPI
VariableCommonInitialize(IN EFI_HANDLE ImageHandle,IN EFI_SYSTEM_TABLE * SystemTable)1756 VariableCommonInitialize (
1757   IN EFI_HANDLE         ImageHandle,
1758   IN EFI_SYSTEM_TABLE   *SystemTable
1759   )
1760 {
1761   EFI_STATUS  Status;
1762 
1763   //
1764   // Allocate memory for mVariableModuleGlobal
1765   //
1766   mVariableModuleGlobal = (ESAL_VARIABLE_GLOBAL *) AllocateRuntimeZeroPool (
1767                                                     sizeof (ESAL_VARIABLE_GLOBAL)
1768                                                    );
1769   if (NULL == mVariableModuleGlobal) {
1770     return EFI_OUT_OF_RESOURCES;
1771   }
1772 
1773   EfiInitializeLock(&mVariableModuleGlobal->VariableGlobal[Physical].VariableServicesLock, TPL_NOTIFY);
1774 
1775   //
1776   // Intialize volatile variable store
1777   //
1778   Status = InitializeVariableStore (TRUE);
1779   if (EFI_ERROR (Status)) {
1780     FreePool(mVariableModuleGlobal);
1781     return Status;
1782   }
1783   //
1784   // Intialize non volatile variable store
1785   //
1786   Status = InitializeVariableStore (FALSE);
1787 
1788   return Status;
1789 }
1790