1 /** @file
2   The common variable operation routines shared by DXE_RUNTIME variable
3   module and DXE_SMM variable module.
4 
5   Caution: This module requires additional review when modified.
6   This driver will have external input - variable data. They may be input in SMM mode.
7   This external input must be validated carefully to avoid security issue like
8   buffer overflow, integer overflow.
9 
10   VariableServiceGetNextVariableName () and VariableServiceQueryVariableInfo() are external API.
11   They need check input parameter.
12 
13   VariableServiceGetVariable() and VariableServiceSetVariable() are external API
14   to receive datasize and data buffer. The size should be checked carefully.
15 
16   VariableServiceSetVariable() should also check authenticate data to avoid buffer overflow,
17   integer overflow. It should also check attribute to avoid authentication bypass.
18 
19 Copyright (c) 2006 - 2019, Intel Corporation. All rights reserved.<BR>
20 (C) Copyright 2015-2018 Hewlett Packard Enterprise Development LP<BR>
21 SPDX-License-Identifier: BSD-2-Clause-Patent
22 
23 **/
24 
25 #include "Variable.h"
26 
27 VARIABLE_MODULE_GLOBAL  *mVariableModuleGlobal;
28 
29 ///
30 /// Define a memory cache that improves the search performance for a variable.
31 /// For EmuNvMode == TRUE, it will be equal to NonVolatileVariableBase.
32 ///
33 VARIABLE_STORE_HEADER  *mNvVariableCache      = NULL;
34 
35 ///
36 /// Memory cache of Fv Header.
37 ///
38 EFI_FIRMWARE_VOLUME_HEADER *mNvFvHeaderCache  = NULL;
39 
40 ///
41 /// The memory entry used for variable statistics data.
42 ///
43 VARIABLE_INFO_ENTRY    *gVariableInfo         = NULL;
44 
45 ///
46 /// The flag to indicate whether the platform has left the DXE phase of execution.
47 ///
48 BOOLEAN                mEndOfDxe              = FALSE;
49 
50 ///
51 /// It indicates the var check request source.
52 /// In the implementation, DXE is regarded as untrusted, and SMM is trusted.
53 ///
54 VAR_CHECK_REQUEST_SOURCE mRequestSource       = VarCheckFromUntrusted;
55 
56 //
57 // It will record the current boot error flag before EndOfDxe.
58 //
59 VAR_ERROR_FLAG         mCurrentBootVarErrFlag = VAR_ERROR_FLAG_NO_ERROR;
60 
61 VARIABLE_ENTRY_PROPERTY mVariableEntryProperty[] = {
62   {
63     &gEdkiiVarErrorFlagGuid,
64     VAR_ERROR_FLAG_NAME,
65     {
66       VAR_CHECK_VARIABLE_PROPERTY_REVISION,
67       VAR_CHECK_VARIABLE_PROPERTY_READ_ONLY,
68       VARIABLE_ATTRIBUTE_NV_BS_RT,
69       sizeof (VAR_ERROR_FLAG),
70       sizeof (VAR_ERROR_FLAG)
71     }
72   },
73 };
74 
75 AUTH_VAR_LIB_CONTEXT_IN mAuthContextIn = {
76   AUTH_VAR_LIB_CONTEXT_IN_STRUCT_VERSION,
77   //
78   // StructSize, TO BE FILLED
79   //
80   0,
81   //
82   // MaxAuthVariableSize, TO BE FILLED
83   //
84   0,
85   VariableExLibFindVariable,
86   VariableExLibFindNextVariable,
87   VariableExLibUpdateVariable,
88   VariableExLibGetScratchBuffer,
89   VariableExLibCheckRemainingSpaceForConsistency,
90   VariableExLibAtRuntime,
91 };
92 
93 AUTH_VAR_LIB_CONTEXT_OUT mAuthContextOut;
94 
95 /**
96   Routine used to track statistical information about variable usage.
97   The data is stored in the EFI system table so it can be accessed later.
98   VariableInfo.efi can dump out the table. Only Boot Services variable
99   accesses are tracked by this code. The PcdVariableCollectStatistics
100   build flag controls if this feature is enabled.
101 
102   A read that hits in the cache will have Read and Cache true for
103   the transaction. Data is allocated by this routine, but never
104   freed.
105 
106   @param[in] VariableName   Name of the Variable to track.
107   @param[in] VendorGuid     Guid of the Variable to track.
108   @param[in] Volatile       TRUE if volatile FALSE if non-volatile.
109   @param[in] Read           TRUE if GetVariable() was called.
110   @param[in] Write          TRUE if SetVariable() was called.
111   @param[in] Delete         TRUE if deleted via SetVariable().
112   @param[in] Cache          TRUE for a cache hit.
113 
114 **/
115 VOID
UpdateVariableInfo(IN CHAR16 * VariableName,IN EFI_GUID * VendorGuid,IN BOOLEAN Volatile,IN BOOLEAN Read,IN BOOLEAN Write,IN BOOLEAN Delete,IN BOOLEAN Cache)116 UpdateVariableInfo (
117   IN  CHAR16                  *VariableName,
118   IN  EFI_GUID                *VendorGuid,
119   IN  BOOLEAN                 Volatile,
120   IN  BOOLEAN                 Read,
121   IN  BOOLEAN                 Write,
122   IN  BOOLEAN                 Delete,
123   IN  BOOLEAN                 Cache
124   )
125 {
126   VARIABLE_INFO_ENTRY   *Entry;
127 
128   if (FeaturePcdGet (PcdVariableCollectStatistics)) {
129 
130     if (AtRuntime ()) {
131       // Don't collect statistics at runtime.
132       return;
133     }
134 
135     if (gVariableInfo == NULL) {
136       //
137       // On the first call allocate a entry and place a pointer to it in
138       // the EFI System Table.
139       //
140       gVariableInfo = AllocateZeroPool (sizeof (VARIABLE_INFO_ENTRY));
141       ASSERT (gVariableInfo != NULL);
142 
143       CopyGuid (&gVariableInfo->VendorGuid, VendorGuid);
144       gVariableInfo->Name = AllocateZeroPool (StrSize (VariableName));
145       ASSERT (gVariableInfo->Name != NULL);
146       StrCpyS (gVariableInfo->Name, StrSize(VariableName)/sizeof(CHAR16), VariableName);
147       gVariableInfo->Volatile = Volatile;
148     }
149 
150 
151     for (Entry = gVariableInfo; Entry != NULL; Entry = Entry->Next) {
152       if (CompareGuid (VendorGuid, &Entry->VendorGuid)) {
153         if (StrCmp (VariableName, Entry->Name) == 0) {
154           if (Read) {
155             Entry->ReadCount++;
156           }
157           if (Write) {
158             Entry->WriteCount++;
159           }
160           if (Delete) {
161             Entry->DeleteCount++;
162           }
163           if (Cache) {
164             Entry->CacheCount++;
165           }
166 
167           return;
168         }
169       }
170 
171       if (Entry->Next == NULL) {
172         //
173         // If the entry is not in the table add it.
174         // Next iteration of the loop will fill in the data.
175         //
176         Entry->Next = AllocateZeroPool (sizeof (VARIABLE_INFO_ENTRY));
177         ASSERT (Entry->Next != NULL);
178 
179         CopyGuid (&Entry->Next->VendorGuid, VendorGuid);
180         Entry->Next->Name = AllocateZeroPool (StrSize (VariableName));
181         ASSERT (Entry->Next->Name != NULL);
182         StrCpyS (Entry->Next->Name, StrSize(VariableName)/sizeof(CHAR16), VariableName);
183         Entry->Next->Volatile = Volatile;
184       }
185 
186     }
187   }
188 }
189 
190 
191 /**
192 
193   This code checks if variable header is valid or not.
194 
195   @param Variable           Pointer to the Variable Header.
196   @param VariableStoreEnd   Pointer to the Variable Store End.
197 
198   @retval TRUE              Variable header is valid.
199   @retval FALSE             Variable header is not valid.
200 
201 **/
202 BOOLEAN
IsValidVariableHeader(IN VARIABLE_HEADER * Variable,IN VARIABLE_HEADER * VariableStoreEnd)203 IsValidVariableHeader (
204   IN  VARIABLE_HEADER       *Variable,
205   IN  VARIABLE_HEADER       *VariableStoreEnd
206   )
207 {
208   if ((Variable == NULL) || (Variable >= VariableStoreEnd) || (Variable->StartId != VARIABLE_DATA)) {
209     //
210     // Variable is NULL or has reached the end of variable store,
211     // or the StartId is not correct.
212     //
213     return FALSE;
214   }
215 
216   return TRUE;
217 }
218 
219 
220 /**
221 
222   This function writes data to the FWH at the correct LBA even if the LBAs
223   are fragmented.
224 
225   @param Global                  Pointer to VARAIBLE_GLOBAL structure.
226   @param Volatile                Point out the Variable is Volatile or Non-Volatile.
227   @param SetByIndex              TRUE if target pointer is given as index.
228                                  FALSE if target pointer is absolute.
229   @param Fvb                     Pointer to the writable FVB protocol.
230   @param DataPtrIndex            Pointer to the Data from the end of VARIABLE_STORE_HEADER
231                                  structure.
232   @param DataSize                Size of data to be written.
233   @param Buffer                  Pointer to the buffer from which data is written.
234 
235   @retval EFI_INVALID_PARAMETER  Parameters not valid.
236   @retval EFI_UNSUPPORTED        Fvb is a NULL for Non-Volatile variable update.
237   @retval EFI_OUT_OF_RESOURCES   The remaining size is not enough.
238   @retval EFI_SUCCESS            Variable store successfully updated.
239 
240 **/
241 EFI_STATUS
UpdateVariableStore(IN VARIABLE_GLOBAL * Global,IN BOOLEAN Volatile,IN BOOLEAN SetByIndex,IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL * Fvb,IN UINTN DataPtrIndex,IN UINT32 DataSize,IN UINT8 * Buffer)242 UpdateVariableStore (
243   IN  VARIABLE_GLOBAL                     *Global,
244   IN  BOOLEAN                             Volatile,
245   IN  BOOLEAN                             SetByIndex,
246   IN  EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL  *Fvb,
247   IN  UINTN                               DataPtrIndex,
248   IN  UINT32                              DataSize,
249   IN  UINT8                               *Buffer
250   )
251 {
252   EFI_FV_BLOCK_MAP_ENTRY      *PtrBlockMapEntry;
253   UINTN                       BlockIndex2;
254   UINTN                       LinearOffset;
255   UINTN                       CurrWriteSize;
256   UINTN                       CurrWritePtr;
257   UINT8                       *CurrBuffer;
258   EFI_LBA                     LbaNumber;
259   UINTN                       Size;
260   VARIABLE_STORE_HEADER       *VolatileBase;
261   EFI_PHYSICAL_ADDRESS        FvVolHdr;
262   EFI_PHYSICAL_ADDRESS        DataPtr;
263   EFI_STATUS                  Status;
264 
265   FvVolHdr    = 0;
266   DataPtr     = DataPtrIndex;
267 
268   //
269   // Check if the Data is Volatile.
270   //
271   if (!Volatile && !mVariableModuleGlobal->VariableGlobal.EmuNvMode) {
272     if (Fvb == NULL) {
273       return EFI_UNSUPPORTED;
274     }
275     Status = Fvb->GetPhysicalAddress(Fvb, &FvVolHdr);
276     ASSERT_EFI_ERROR (Status);
277 
278     //
279     // Data Pointer should point to the actual Address where data is to be
280     // written.
281     //
282     if (SetByIndex) {
283       DataPtr += mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase;
284     }
285 
286     if ((DataPtr + DataSize) > (FvVolHdr + mNvFvHeaderCache->FvLength)) {
287       return EFI_OUT_OF_RESOURCES;
288     }
289   } else {
290     //
291     // Data Pointer should point to the actual Address where data is to be
292     // written.
293     //
294     if (Volatile) {
295       VolatileBase = (VARIABLE_STORE_HEADER *) ((UINTN) mVariableModuleGlobal->VariableGlobal.VolatileVariableBase);
296       if (SetByIndex) {
297         DataPtr += mVariableModuleGlobal->VariableGlobal.VolatileVariableBase;
298       }
299 
300       if ((DataPtr + DataSize) > ((UINTN) VolatileBase + VolatileBase->Size)) {
301         return EFI_OUT_OF_RESOURCES;
302       }
303     } else {
304       //
305       // Emulated non-volatile variable mode.
306       //
307       if (SetByIndex) {
308         DataPtr += (UINTN) mNvVariableCache;
309       }
310 
311       if ((DataPtr + DataSize) > ((UINTN) mNvVariableCache + mNvVariableCache->Size)) {
312         return EFI_OUT_OF_RESOURCES;
313       }
314     }
315 
316     //
317     // If Volatile/Emulated Non-volatile Variable just do a simple mem copy.
318     //
319     CopyMem ((UINT8 *)(UINTN)DataPtr, Buffer, DataSize);
320     return EFI_SUCCESS;
321   }
322 
323   //
324   // If we are here we are dealing with Non-Volatile Variables.
325   //
326   LinearOffset  = (UINTN) FvVolHdr;
327   CurrWritePtr  = (UINTN) DataPtr;
328   CurrWriteSize = DataSize;
329   CurrBuffer    = Buffer;
330   LbaNumber     = 0;
331 
332   if (CurrWritePtr < LinearOffset) {
333     return EFI_INVALID_PARAMETER;
334   }
335 
336   for (PtrBlockMapEntry = mNvFvHeaderCache->BlockMap; PtrBlockMapEntry->NumBlocks != 0; PtrBlockMapEntry++) {
337     for (BlockIndex2 = 0; BlockIndex2 < PtrBlockMapEntry->NumBlocks; BlockIndex2++) {
338       //
339       // Check to see if the Variable Writes are spanning through multiple
340       // blocks.
341       //
342       if ((CurrWritePtr >= LinearOffset) && (CurrWritePtr < LinearOffset + PtrBlockMapEntry->Length)) {
343         if ((CurrWritePtr + CurrWriteSize) <= (LinearOffset + PtrBlockMapEntry->Length)) {
344           Status = Fvb->Write (
345                     Fvb,
346                     LbaNumber,
347                     (UINTN) (CurrWritePtr - LinearOffset),
348                     &CurrWriteSize,
349                     CurrBuffer
350                     );
351           return Status;
352         } else {
353           Size = (UINT32) (LinearOffset + PtrBlockMapEntry->Length - CurrWritePtr);
354           Status = Fvb->Write (
355                     Fvb,
356                     LbaNumber,
357                     (UINTN) (CurrWritePtr - LinearOffset),
358                     &Size,
359                     CurrBuffer
360                     );
361           if (EFI_ERROR (Status)) {
362             return Status;
363           }
364 
365           CurrWritePtr  = LinearOffset + PtrBlockMapEntry->Length;
366           CurrBuffer    = CurrBuffer + Size;
367           CurrWriteSize = CurrWriteSize - Size;
368         }
369       }
370 
371       LinearOffset += PtrBlockMapEntry->Length;
372       LbaNumber++;
373     }
374   }
375 
376   return EFI_SUCCESS;
377 }
378 
379 
380 /**
381 
382   This code gets the current status of Variable Store.
383 
384   @param VarStoreHeader  Pointer to the Variable Store Header.
385 
386   @retval EfiRaw         Variable store status is raw.
387   @retval EfiValid       Variable store status is valid.
388   @retval EfiInvalid     Variable store status is invalid.
389 
390 **/
391 VARIABLE_STORE_STATUS
GetVariableStoreStatus(IN VARIABLE_STORE_HEADER * VarStoreHeader)392 GetVariableStoreStatus (
393   IN VARIABLE_STORE_HEADER *VarStoreHeader
394   )
395 {
396   if ((CompareGuid (&VarStoreHeader->Signature, &gEfiAuthenticatedVariableGuid) ||
397        CompareGuid (&VarStoreHeader->Signature, &gEfiVariableGuid)) &&
398       VarStoreHeader->Format == VARIABLE_STORE_FORMATTED &&
399       VarStoreHeader->State == VARIABLE_STORE_HEALTHY
400       ) {
401 
402     return EfiValid;
403   } else if (((UINT32 *)(&VarStoreHeader->Signature))[0] == 0xffffffff &&
404              ((UINT32 *)(&VarStoreHeader->Signature))[1] == 0xffffffff &&
405              ((UINT32 *)(&VarStoreHeader->Signature))[2] == 0xffffffff &&
406              ((UINT32 *)(&VarStoreHeader->Signature))[3] == 0xffffffff &&
407              VarStoreHeader->Size == 0xffffffff &&
408              VarStoreHeader->Format == 0xff &&
409              VarStoreHeader->State == 0xff
410           ) {
411 
412     return EfiRaw;
413   } else {
414     return EfiInvalid;
415   }
416 }
417 
418 /**
419   This code gets the size of variable header.
420 
421   @return Size of variable header in bytes in type UINTN.
422 
423 **/
424 UINTN
GetVariableHeaderSize(VOID)425 GetVariableHeaderSize (
426   VOID
427   )
428 {
429   UINTN Value;
430 
431   if (mVariableModuleGlobal->VariableGlobal.AuthFormat) {
432     Value = sizeof (AUTHENTICATED_VARIABLE_HEADER);
433   } else {
434     Value = sizeof (VARIABLE_HEADER);
435   }
436 
437   return Value;
438 }
439 
440 /**
441 
442   This code gets the size of name of variable.
443 
444   @param Variable        Pointer to the Variable Header.
445 
446   @return UINTN          Size of variable in bytes.
447 
448 **/
449 UINTN
NameSizeOfVariable(IN VARIABLE_HEADER * Variable)450 NameSizeOfVariable (
451   IN  VARIABLE_HEADER   *Variable
452   )
453 {
454   AUTHENTICATED_VARIABLE_HEADER *AuthVariable;
455 
456   AuthVariable = (AUTHENTICATED_VARIABLE_HEADER *) Variable;
457   if (mVariableModuleGlobal->VariableGlobal.AuthFormat) {
458     if (AuthVariable->State == (UINT8) (-1) ||
459        AuthVariable->DataSize == (UINT32) (-1) ||
460        AuthVariable->NameSize == (UINT32) (-1) ||
461        AuthVariable->Attributes == (UINT32) (-1)) {
462       return 0;
463     }
464     return (UINTN) AuthVariable->NameSize;
465   } else {
466     if (Variable->State == (UINT8) (-1) ||
467         Variable->DataSize == (UINT32) (-1) ||
468         Variable->NameSize == (UINT32) (-1) ||
469         Variable->Attributes == (UINT32) (-1)) {
470       return 0;
471     }
472     return (UINTN) Variable->NameSize;
473   }
474 }
475 
476 /**
477   This code sets the size of name of variable.
478 
479   @param[in] Variable   Pointer to the Variable Header.
480   @param[in] NameSize   Name size to set.
481 
482 **/
483 VOID
SetNameSizeOfVariable(IN VARIABLE_HEADER * Variable,IN UINTN NameSize)484 SetNameSizeOfVariable (
485   IN VARIABLE_HEADER    *Variable,
486   IN UINTN              NameSize
487   )
488 {
489   AUTHENTICATED_VARIABLE_HEADER *AuthVariable;
490 
491   AuthVariable = (AUTHENTICATED_VARIABLE_HEADER *) Variable;
492   if (mVariableModuleGlobal->VariableGlobal.AuthFormat) {
493     AuthVariable->NameSize = (UINT32) NameSize;
494   } else {
495     Variable->NameSize = (UINT32) NameSize;
496   }
497 }
498 
499 /**
500 
501   This code gets the size of variable data.
502 
503   @param Variable        Pointer to the Variable Header.
504 
505   @return Size of variable in bytes.
506 
507 **/
508 UINTN
DataSizeOfVariable(IN VARIABLE_HEADER * Variable)509 DataSizeOfVariable (
510   IN  VARIABLE_HEADER   *Variable
511   )
512 {
513   AUTHENTICATED_VARIABLE_HEADER *AuthVariable;
514 
515   AuthVariable = (AUTHENTICATED_VARIABLE_HEADER *) Variable;
516   if (mVariableModuleGlobal->VariableGlobal.AuthFormat) {
517     if (AuthVariable->State == (UINT8) (-1) ||
518        AuthVariable->DataSize == (UINT32) (-1) ||
519        AuthVariable->NameSize == (UINT32) (-1) ||
520        AuthVariable->Attributes == (UINT32) (-1)) {
521       return 0;
522     }
523     return (UINTN) AuthVariable->DataSize;
524   } else {
525     if (Variable->State == (UINT8) (-1) ||
526         Variable->DataSize == (UINT32) (-1) ||
527         Variable->NameSize == (UINT32) (-1) ||
528         Variable->Attributes == (UINT32) (-1)) {
529       return 0;
530     }
531     return (UINTN) Variable->DataSize;
532   }
533 }
534 
535 /**
536   This code sets the size of variable data.
537 
538   @param[in] Variable   Pointer to the Variable Header.
539   @param[in] DataSize   Data size to set.
540 
541 **/
542 VOID
SetDataSizeOfVariable(IN VARIABLE_HEADER * Variable,IN UINTN DataSize)543 SetDataSizeOfVariable (
544   IN VARIABLE_HEADER    *Variable,
545   IN UINTN              DataSize
546   )
547 {
548   AUTHENTICATED_VARIABLE_HEADER *AuthVariable;
549 
550   AuthVariable = (AUTHENTICATED_VARIABLE_HEADER *) Variable;
551   if (mVariableModuleGlobal->VariableGlobal.AuthFormat) {
552     AuthVariable->DataSize = (UINT32) DataSize;
553   } else {
554     Variable->DataSize = (UINT32) DataSize;
555   }
556 }
557 
558 /**
559 
560   This code gets the pointer to the variable name.
561 
562   @param Variable        Pointer to the Variable Header.
563 
564   @return Pointer to Variable Name which is Unicode encoding.
565 
566 **/
567 CHAR16 *
GetVariableNamePtr(IN VARIABLE_HEADER * Variable)568 GetVariableNamePtr (
569   IN  VARIABLE_HEADER   *Variable
570   )
571 {
572   return (CHAR16 *) ((UINTN) Variable + GetVariableHeaderSize ());
573 }
574 
575 /**
576   This code gets the pointer to the variable guid.
577 
578   @param Variable   Pointer to the Variable Header.
579 
580   @return A EFI_GUID* pointer to Vendor Guid.
581 
582 **/
583 EFI_GUID *
GetVendorGuidPtr(IN VARIABLE_HEADER * Variable)584 GetVendorGuidPtr (
585   IN VARIABLE_HEADER    *Variable
586   )
587 {
588   AUTHENTICATED_VARIABLE_HEADER *AuthVariable;
589 
590   AuthVariable = (AUTHENTICATED_VARIABLE_HEADER *) Variable;
591   if (mVariableModuleGlobal->VariableGlobal.AuthFormat) {
592     return &AuthVariable->VendorGuid;
593   } else {
594     return &Variable->VendorGuid;
595   }
596 }
597 
598 /**
599 
600   This code gets the pointer to the variable data.
601 
602   @param Variable        Pointer to the Variable Header.
603 
604   @return Pointer to Variable Data.
605 
606 **/
607 UINT8 *
GetVariableDataPtr(IN VARIABLE_HEADER * Variable)608 GetVariableDataPtr (
609   IN  VARIABLE_HEADER   *Variable
610   )
611 {
612   UINTN Value;
613 
614   //
615   // Be careful about pad size for alignment.
616   //
617   Value =  (UINTN) GetVariableNamePtr (Variable);
618   Value += NameSizeOfVariable (Variable);
619   Value += GET_PAD_SIZE (NameSizeOfVariable (Variable));
620 
621   return (UINT8 *) Value;
622 }
623 
624 /**
625   This code gets the variable data offset related to variable header.
626 
627   @param Variable        Pointer to the Variable Header.
628 
629   @return Variable Data offset.
630 
631 **/
632 UINTN
GetVariableDataOffset(IN VARIABLE_HEADER * Variable)633 GetVariableDataOffset (
634   IN  VARIABLE_HEADER   *Variable
635   )
636 {
637   UINTN Value;
638 
639   //
640   // Be careful about pad size for alignment
641   //
642   Value = GetVariableHeaderSize ();
643   Value += NameSizeOfVariable (Variable);
644   Value += GET_PAD_SIZE (NameSizeOfVariable (Variable));
645 
646   return Value;
647 }
648 
649 /**
650 
651   This code gets the pointer to the next variable header.
652 
653   @param Variable        Pointer to the Variable Header.
654 
655   @return Pointer to next variable header.
656 
657 **/
658 VARIABLE_HEADER *
GetNextVariablePtr(IN VARIABLE_HEADER * Variable)659 GetNextVariablePtr (
660   IN  VARIABLE_HEADER   *Variable
661   )
662 {
663   UINTN Value;
664 
665   Value =  (UINTN) GetVariableDataPtr (Variable);
666   Value += DataSizeOfVariable (Variable);
667   Value += GET_PAD_SIZE (DataSizeOfVariable (Variable));
668 
669   //
670   // Be careful about pad size for alignment.
671   //
672   return (VARIABLE_HEADER *) HEADER_ALIGN (Value);
673 }
674 
675 /**
676 
677   Gets the pointer to the first variable header in given variable store area.
678 
679   @param VarStoreHeader  Pointer to the Variable Store Header.
680 
681   @return Pointer to the first variable header.
682 
683 **/
684 VARIABLE_HEADER *
GetStartPointer(IN VARIABLE_STORE_HEADER * VarStoreHeader)685 GetStartPointer (
686   IN VARIABLE_STORE_HEADER       *VarStoreHeader
687   )
688 {
689   //
690   // The start of variable store.
691   //
692   return (VARIABLE_HEADER *) HEADER_ALIGN (VarStoreHeader + 1);
693 }
694 
695 /**
696 
697   Gets the pointer to the end of the variable storage area.
698 
699   This function gets pointer to the end of the variable storage
700   area, according to the input variable store header.
701 
702   @param VarStoreHeader  Pointer to the Variable Store Header.
703 
704   @return Pointer to the end of the variable storage area.
705 
706 **/
707 VARIABLE_HEADER *
GetEndPointer(IN VARIABLE_STORE_HEADER * VarStoreHeader)708 GetEndPointer (
709   IN VARIABLE_STORE_HEADER       *VarStoreHeader
710   )
711 {
712   //
713   // The end of variable store
714   //
715   return (VARIABLE_HEADER *) HEADER_ALIGN ((UINTN) VarStoreHeader + VarStoreHeader->Size);
716 }
717 
718 /**
719   Record variable error flag.
720 
721   @param[in] Flag               Variable error flag to record.
722   @param[in] VariableName       Name of variable.
723   @param[in] VendorGuid         Guid of variable.
724   @param[in] Attributes         Attributes of the variable.
725   @param[in] VariableSize       Size of the variable.
726 
727 **/
728 VOID
RecordVarErrorFlag(IN VAR_ERROR_FLAG Flag,IN CHAR16 * VariableName,IN EFI_GUID * VendorGuid,IN UINT32 Attributes,IN UINTN VariableSize)729 RecordVarErrorFlag (
730   IN VAR_ERROR_FLAG         Flag,
731   IN CHAR16                 *VariableName,
732   IN EFI_GUID               *VendorGuid,
733   IN UINT32                 Attributes,
734   IN UINTN                  VariableSize
735   )
736 {
737   EFI_STATUS                Status;
738   VARIABLE_POINTER_TRACK    Variable;
739   VAR_ERROR_FLAG            *VarErrFlag;
740   VAR_ERROR_FLAG            TempFlag;
741 
742   DEBUG_CODE (
743     DEBUG ((EFI_D_ERROR, "RecordVarErrorFlag (0x%02x) %s:%g - 0x%08x - 0x%x\n", Flag, VariableName, VendorGuid, Attributes, VariableSize));
744     if (Flag == VAR_ERROR_FLAG_SYSTEM_ERROR) {
745       if (AtRuntime ()) {
746         DEBUG ((EFI_D_ERROR, "CommonRuntimeVariableSpace = 0x%x - CommonVariableTotalSize = 0x%x\n", mVariableModuleGlobal->CommonRuntimeVariableSpace, mVariableModuleGlobal->CommonVariableTotalSize));
747       } else {
748         DEBUG ((EFI_D_ERROR, "CommonVariableSpace = 0x%x - CommonVariableTotalSize = 0x%x\n", mVariableModuleGlobal->CommonVariableSpace, mVariableModuleGlobal->CommonVariableTotalSize));
749       }
750     } else {
751       DEBUG ((EFI_D_ERROR, "CommonMaxUserVariableSpace = 0x%x - CommonUserVariableTotalSize = 0x%x\n", mVariableModuleGlobal->CommonMaxUserVariableSpace, mVariableModuleGlobal->CommonUserVariableTotalSize));
752     }
753   );
754 
755   if (!mEndOfDxe) {
756     //
757     // Before EndOfDxe, just record the current boot variable error flag to local variable,
758     // and leave the variable error flag in NV flash as the last boot variable error flag.
759     // After EndOfDxe in InitializeVarErrorFlag (), the variable error flag in NV flash
760     // will be initialized to this local current boot variable error flag.
761     //
762     mCurrentBootVarErrFlag &= Flag;
763     return;
764   }
765 
766   //
767   // Record error flag (it should have be initialized).
768   //
769   Status = FindVariable (
770              VAR_ERROR_FLAG_NAME,
771              &gEdkiiVarErrorFlagGuid,
772              &Variable,
773              &mVariableModuleGlobal->VariableGlobal,
774              FALSE
775              );
776   if (!EFI_ERROR (Status)) {
777     VarErrFlag = (VAR_ERROR_FLAG *) GetVariableDataPtr (Variable.CurrPtr);
778     TempFlag = *VarErrFlag;
779     TempFlag &= Flag;
780     if (TempFlag == *VarErrFlag) {
781       return;
782     }
783     Status = UpdateVariableStore (
784                &mVariableModuleGlobal->VariableGlobal,
785                FALSE,
786                FALSE,
787                mVariableModuleGlobal->FvbInstance,
788                (UINTN) VarErrFlag - (UINTN) mNvVariableCache + (UINTN) mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase,
789                sizeof (TempFlag),
790                &TempFlag
791                );
792     if (!EFI_ERROR (Status)) {
793       //
794       // Update the data in NV cache.
795       //
796       *VarErrFlag = TempFlag;
797     }
798   }
799 }
800 
801 /**
802   Initialize variable error flag.
803 
804   Before EndOfDxe, the variable indicates the last boot variable error flag,
805   then it means the last boot variable error flag must be got before EndOfDxe.
806   After EndOfDxe, the variable indicates the current boot variable error flag,
807   then it means the current boot variable error flag must be got after EndOfDxe.
808 
809 **/
810 VOID
InitializeVarErrorFlag(VOID)811 InitializeVarErrorFlag (
812   VOID
813   )
814 {
815   EFI_STATUS                Status;
816   VARIABLE_POINTER_TRACK    Variable;
817   VAR_ERROR_FLAG            Flag;
818   VAR_ERROR_FLAG            VarErrFlag;
819 
820   if (!mEndOfDxe) {
821     return;
822   }
823 
824   Flag = mCurrentBootVarErrFlag;
825   DEBUG ((EFI_D_INFO, "Initialize variable error flag (%02x)\n", Flag));
826 
827   Status = FindVariable (
828              VAR_ERROR_FLAG_NAME,
829              &gEdkiiVarErrorFlagGuid,
830              &Variable,
831              &mVariableModuleGlobal->VariableGlobal,
832              FALSE
833              );
834   if (!EFI_ERROR (Status)) {
835     VarErrFlag = *((VAR_ERROR_FLAG *) GetVariableDataPtr (Variable.CurrPtr));
836     if (VarErrFlag == Flag) {
837       return;
838     }
839   }
840 
841   UpdateVariable (
842     VAR_ERROR_FLAG_NAME,
843     &gEdkiiVarErrorFlagGuid,
844     &Flag,
845     sizeof (Flag),
846     VARIABLE_ATTRIBUTE_NV_BS_RT,
847     0,
848     0,
849     &Variable,
850     NULL
851     );
852 }
853 
854 /**
855   Is user variable?
856 
857   @param[in] Variable   Pointer to variable header.
858 
859   @retval TRUE          User variable.
860   @retval FALSE         System variable.
861 
862 **/
863 BOOLEAN
IsUserVariable(IN VARIABLE_HEADER * Variable)864 IsUserVariable (
865   IN VARIABLE_HEADER    *Variable
866   )
867 {
868   VAR_CHECK_VARIABLE_PROPERTY   Property;
869 
870   //
871   // Only after End Of Dxe, the variables belong to system variable are fixed.
872   // If PcdMaxUserNvStorageVariableSize is 0, it means user variable share the same NV storage with system variable,
873   // then no need to check if the variable is user variable or not specially.
874   //
875   if (mEndOfDxe && (mVariableModuleGlobal->CommonMaxUserVariableSpace != mVariableModuleGlobal->CommonVariableSpace)) {
876     if (VarCheckLibVariablePropertyGet (GetVariableNamePtr (Variable), GetVendorGuidPtr (Variable), &Property) == EFI_NOT_FOUND) {
877       return TRUE;
878     }
879   }
880   return FALSE;
881 }
882 
883 /**
884   Calculate common user variable total size.
885 
886 **/
887 VOID
CalculateCommonUserVariableTotalSize(VOID)888 CalculateCommonUserVariableTotalSize (
889   VOID
890   )
891 {
892   VARIABLE_HEADER               *Variable;
893   VARIABLE_HEADER               *NextVariable;
894   UINTN                         VariableSize;
895   VAR_CHECK_VARIABLE_PROPERTY   Property;
896 
897   //
898   // Only after End Of Dxe, the variables belong to system variable are fixed.
899   // If PcdMaxUserNvStorageVariableSize is 0, it means user variable share the same NV storage with system variable,
900   // then no need to calculate the common user variable total size specially.
901   //
902   if (mEndOfDxe && (mVariableModuleGlobal->CommonMaxUserVariableSpace != mVariableModuleGlobal->CommonVariableSpace)) {
903     Variable = GetStartPointer (mNvVariableCache);
904     while (IsValidVariableHeader (Variable, GetEndPointer (mNvVariableCache))) {
905       NextVariable = GetNextVariablePtr (Variable);
906       VariableSize = (UINTN) NextVariable - (UINTN) Variable;
907       if ((Variable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) != EFI_VARIABLE_HARDWARE_ERROR_RECORD) {
908         if (VarCheckLibVariablePropertyGet (GetVariableNamePtr (Variable), GetVendorGuidPtr (Variable), &Property) == EFI_NOT_FOUND) {
909           //
910           // No property, it is user variable.
911           //
912           mVariableModuleGlobal->CommonUserVariableTotalSize += VariableSize;
913         }
914       }
915 
916       Variable = NextVariable;
917     }
918   }
919 }
920 
921 /**
922   Initialize variable quota.
923 
924 **/
925 VOID
InitializeVariableQuota(VOID)926 InitializeVariableQuota (
927   VOID
928   )
929 {
930   if (!mEndOfDxe) {
931     return;
932   }
933 
934   InitializeVarErrorFlag ();
935   CalculateCommonUserVariableTotalSize ();
936 }
937 
938 /**
939 
940   Variable store garbage collection and reclaim operation.
941 
942   @param[in]      VariableBase            Base address of variable store.
943   @param[out]     LastVariableOffset      Offset of last variable.
944   @param[in]      IsVolatile              The variable store is volatile or not;
945                                           if it is non-volatile, need FTW.
946   @param[in, out] UpdatingPtrTrack        Pointer to updating variable pointer track structure.
947   @param[in]      NewVariable             Pointer to new variable.
948   @param[in]      NewVariableSize         New variable size.
949 
950   @return EFI_SUCCESS                  Reclaim operation has finished successfully.
951   @return EFI_OUT_OF_RESOURCES         No enough memory resources or variable space.
952   @return Others                       Unexpect error happened during reclaim operation.
953 
954 **/
955 EFI_STATUS
Reclaim(IN EFI_PHYSICAL_ADDRESS VariableBase,OUT UINTN * LastVariableOffset,IN BOOLEAN IsVolatile,IN OUT VARIABLE_POINTER_TRACK * UpdatingPtrTrack,IN VARIABLE_HEADER * NewVariable,IN UINTN NewVariableSize)956 Reclaim (
957   IN     EFI_PHYSICAL_ADDRESS         VariableBase,
958   OUT    UINTN                        *LastVariableOffset,
959   IN     BOOLEAN                      IsVolatile,
960   IN OUT VARIABLE_POINTER_TRACK       *UpdatingPtrTrack,
961   IN     VARIABLE_HEADER              *NewVariable,
962   IN     UINTN                        NewVariableSize
963   )
964 {
965   VARIABLE_HEADER       *Variable;
966   VARIABLE_HEADER       *AddedVariable;
967   VARIABLE_HEADER       *NextVariable;
968   VARIABLE_HEADER       *NextAddedVariable;
969   VARIABLE_STORE_HEADER *VariableStoreHeader;
970   UINT8                 *ValidBuffer;
971   UINTN                 MaximumBufferSize;
972   UINTN                 VariableSize;
973   UINTN                 NameSize;
974   UINT8                 *CurrPtr;
975   VOID                  *Point0;
976   VOID                  *Point1;
977   BOOLEAN               FoundAdded;
978   EFI_STATUS            Status;
979   UINTN                 CommonVariableTotalSize;
980   UINTN                 CommonUserVariableTotalSize;
981   UINTN                 HwErrVariableTotalSize;
982   VARIABLE_HEADER       *UpdatingVariable;
983   VARIABLE_HEADER       *UpdatingInDeletedTransition;
984 
985   UpdatingVariable = NULL;
986   UpdatingInDeletedTransition = NULL;
987   if (UpdatingPtrTrack != NULL) {
988     UpdatingVariable = UpdatingPtrTrack->CurrPtr;
989     UpdatingInDeletedTransition = UpdatingPtrTrack->InDeletedTransitionPtr;
990   }
991 
992   VariableStoreHeader = (VARIABLE_STORE_HEADER *) ((UINTN) VariableBase);
993 
994   CommonVariableTotalSize = 0;
995   CommonUserVariableTotalSize = 0;
996   HwErrVariableTotalSize  = 0;
997 
998   if (IsVolatile || mVariableModuleGlobal->VariableGlobal.EmuNvMode) {
999     //
1000     // Start Pointers for the variable.
1001     //
1002     Variable          = GetStartPointer (VariableStoreHeader);
1003     MaximumBufferSize = sizeof (VARIABLE_STORE_HEADER);
1004 
1005     while (IsValidVariableHeader (Variable, GetEndPointer (VariableStoreHeader))) {
1006       NextVariable = GetNextVariablePtr (Variable);
1007       if ((Variable->State == VAR_ADDED || Variable->State == (VAR_IN_DELETED_TRANSITION & VAR_ADDED)) &&
1008           Variable != UpdatingVariable &&
1009           Variable != UpdatingInDeletedTransition
1010          ) {
1011         VariableSize = (UINTN) NextVariable - (UINTN) Variable;
1012         MaximumBufferSize += VariableSize;
1013       }
1014 
1015       Variable = NextVariable;
1016     }
1017 
1018     if (NewVariable != NULL) {
1019       //
1020       // Add the new variable size.
1021       //
1022       MaximumBufferSize += NewVariableSize;
1023     }
1024 
1025     //
1026     // Reserve the 1 Bytes with Oxff to identify the
1027     // end of the variable buffer.
1028     //
1029     MaximumBufferSize += 1;
1030     ValidBuffer = AllocatePool (MaximumBufferSize);
1031     if (ValidBuffer == NULL) {
1032       return EFI_OUT_OF_RESOURCES;
1033     }
1034   } else {
1035     //
1036     // For NV variable reclaim, don't allocate pool here and just use mNvVariableCache
1037     // as the buffer to reduce SMRAM consumption for SMM variable driver.
1038     //
1039     MaximumBufferSize = mNvVariableCache->Size;
1040     ValidBuffer = (UINT8 *) mNvVariableCache;
1041   }
1042 
1043   SetMem (ValidBuffer, MaximumBufferSize, 0xff);
1044 
1045   //
1046   // Copy variable store header.
1047   //
1048   CopyMem (ValidBuffer, VariableStoreHeader, sizeof (VARIABLE_STORE_HEADER));
1049   CurrPtr = (UINT8 *) GetStartPointer ((VARIABLE_STORE_HEADER *) ValidBuffer);
1050 
1051   //
1052   // Reinstall all ADDED variables as long as they are not identical to Updating Variable.
1053   //
1054   Variable = GetStartPointer (VariableStoreHeader);
1055   while (IsValidVariableHeader (Variable, GetEndPointer (VariableStoreHeader))) {
1056     NextVariable = GetNextVariablePtr (Variable);
1057     if (Variable != UpdatingVariable && Variable->State == VAR_ADDED) {
1058       VariableSize = (UINTN) NextVariable - (UINTN) Variable;
1059       CopyMem (CurrPtr, (UINT8 *) Variable, VariableSize);
1060       CurrPtr += VariableSize;
1061       if ((!IsVolatile) && ((Variable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == EFI_VARIABLE_HARDWARE_ERROR_RECORD)) {
1062         HwErrVariableTotalSize += VariableSize;
1063       } else if ((!IsVolatile) && ((Variable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) != EFI_VARIABLE_HARDWARE_ERROR_RECORD)) {
1064         CommonVariableTotalSize += VariableSize;
1065         if (IsUserVariable (Variable)) {
1066           CommonUserVariableTotalSize += VariableSize;
1067         }
1068       }
1069     }
1070     Variable = NextVariable;
1071   }
1072 
1073   //
1074   // Reinstall all in delete transition variables.
1075   //
1076   Variable = GetStartPointer (VariableStoreHeader);
1077   while (IsValidVariableHeader (Variable, GetEndPointer (VariableStoreHeader))) {
1078     NextVariable = GetNextVariablePtr (Variable);
1079     if (Variable != UpdatingVariable && Variable != UpdatingInDeletedTransition && Variable->State == (VAR_IN_DELETED_TRANSITION & VAR_ADDED)) {
1080 
1081       //
1082       // Buffer has cached all ADDED variable.
1083       // Per IN_DELETED variable, we have to guarantee that
1084       // no ADDED one in previous buffer.
1085       //
1086 
1087       FoundAdded = FALSE;
1088       AddedVariable = GetStartPointer ((VARIABLE_STORE_HEADER *) ValidBuffer);
1089       while (IsValidVariableHeader (AddedVariable, GetEndPointer ((VARIABLE_STORE_HEADER *) ValidBuffer))) {
1090         NextAddedVariable = GetNextVariablePtr (AddedVariable);
1091         NameSize = NameSizeOfVariable (AddedVariable);
1092         if (CompareGuid (GetVendorGuidPtr (AddedVariable), GetVendorGuidPtr (Variable)) &&
1093             NameSize == NameSizeOfVariable (Variable)
1094            ) {
1095           Point0 = (VOID *) GetVariableNamePtr (AddedVariable);
1096           Point1 = (VOID *) GetVariableNamePtr (Variable);
1097           if (CompareMem (Point0, Point1, NameSize) == 0) {
1098             FoundAdded = TRUE;
1099             break;
1100           }
1101         }
1102         AddedVariable = NextAddedVariable;
1103       }
1104       if (!FoundAdded) {
1105         //
1106         // Promote VAR_IN_DELETED_TRANSITION to VAR_ADDED.
1107         //
1108         VariableSize = (UINTN) NextVariable - (UINTN) Variable;
1109         CopyMem (CurrPtr, (UINT8 *) Variable, VariableSize);
1110         ((VARIABLE_HEADER *) CurrPtr)->State = VAR_ADDED;
1111         CurrPtr += VariableSize;
1112         if ((!IsVolatile) && ((Variable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == EFI_VARIABLE_HARDWARE_ERROR_RECORD)) {
1113           HwErrVariableTotalSize += VariableSize;
1114         } else if ((!IsVolatile) && ((Variable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) != EFI_VARIABLE_HARDWARE_ERROR_RECORD)) {
1115           CommonVariableTotalSize += VariableSize;
1116           if (IsUserVariable (Variable)) {
1117             CommonUserVariableTotalSize += VariableSize;
1118           }
1119         }
1120       }
1121     }
1122 
1123     Variable = NextVariable;
1124   }
1125 
1126   //
1127   // Install the new variable if it is not NULL.
1128   //
1129   if (NewVariable != NULL) {
1130     if (((UINTN) CurrPtr - (UINTN) ValidBuffer) + NewVariableSize > VariableStoreHeader->Size) {
1131       //
1132       // No enough space to store the new variable.
1133       //
1134       Status = EFI_OUT_OF_RESOURCES;
1135       goto Done;
1136     }
1137     if (!IsVolatile) {
1138       if ((NewVariable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == EFI_VARIABLE_HARDWARE_ERROR_RECORD) {
1139         HwErrVariableTotalSize += NewVariableSize;
1140       } else if ((NewVariable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) != EFI_VARIABLE_HARDWARE_ERROR_RECORD) {
1141         CommonVariableTotalSize += NewVariableSize;
1142         if (IsUserVariable (NewVariable)) {
1143           CommonUserVariableTotalSize += NewVariableSize;
1144         }
1145       }
1146       if ((HwErrVariableTotalSize > PcdGet32 (PcdHwErrStorageSize)) ||
1147           (CommonVariableTotalSize > mVariableModuleGlobal->CommonVariableSpace) ||
1148           (CommonUserVariableTotalSize > mVariableModuleGlobal->CommonMaxUserVariableSpace)) {
1149         //
1150         // No enough space to store the new variable by NV or NV+HR attribute.
1151         //
1152         Status = EFI_OUT_OF_RESOURCES;
1153         goto Done;
1154       }
1155     }
1156 
1157     CopyMem (CurrPtr, (UINT8 *) NewVariable, NewVariableSize);
1158     ((VARIABLE_HEADER *) CurrPtr)->State = VAR_ADDED;
1159     if (UpdatingVariable != NULL) {
1160       UpdatingPtrTrack->CurrPtr = (VARIABLE_HEADER *)((UINTN)UpdatingPtrTrack->StartPtr + ((UINTN)CurrPtr - (UINTN)GetStartPointer ((VARIABLE_STORE_HEADER *) ValidBuffer)));
1161       UpdatingPtrTrack->InDeletedTransitionPtr = NULL;
1162     }
1163     CurrPtr += NewVariableSize;
1164   }
1165 
1166   if (IsVolatile || mVariableModuleGlobal->VariableGlobal.EmuNvMode) {
1167     //
1168     // If volatile/emulated non-volatile variable store, just copy valid buffer.
1169     //
1170     SetMem ((UINT8 *) (UINTN) VariableBase, VariableStoreHeader->Size, 0xff);
1171     CopyMem ((UINT8 *) (UINTN) VariableBase, ValidBuffer, (UINTN) CurrPtr - (UINTN) ValidBuffer);
1172     *LastVariableOffset = (UINTN) CurrPtr - (UINTN) ValidBuffer;
1173     if (!IsVolatile) {
1174       //
1175       // Emulated non-volatile variable mode.
1176       //
1177       mVariableModuleGlobal->HwErrVariableTotalSize = HwErrVariableTotalSize;
1178       mVariableModuleGlobal->CommonVariableTotalSize = CommonVariableTotalSize;
1179       mVariableModuleGlobal->CommonUserVariableTotalSize = CommonUserVariableTotalSize;
1180     }
1181     Status  = EFI_SUCCESS;
1182   } else {
1183     //
1184     // If non-volatile variable store, perform FTW here.
1185     //
1186     Status = FtwVariableSpace (
1187               VariableBase,
1188               (VARIABLE_STORE_HEADER *) ValidBuffer
1189               );
1190     if (!EFI_ERROR (Status)) {
1191       *LastVariableOffset = (UINTN) CurrPtr - (UINTN) ValidBuffer;
1192       mVariableModuleGlobal->HwErrVariableTotalSize = HwErrVariableTotalSize;
1193       mVariableModuleGlobal->CommonVariableTotalSize = CommonVariableTotalSize;
1194       mVariableModuleGlobal->CommonUserVariableTotalSize = CommonUserVariableTotalSize;
1195     } else {
1196       mVariableModuleGlobal->HwErrVariableTotalSize = 0;
1197       mVariableModuleGlobal->CommonVariableTotalSize = 0;
1198       mVariableModuleGlobal->CommonUserVariableTotalSize = 0;
1199       Variable = GetStartPointer ((VARIABLE_STORE_HEADER *)(UINTN)VariableBase);
1200       while (IsValidVariableHeader (Variable, GetEndPointer ((VARIABLE_STORE_HEADER *)(UINTN)VariableBase))) {
1201         NextVariable = GetNextVariablePtr (Variable);
1202         VariableSize = (UINTN) NextVariable - (UINTN) Variable;
1203         if ((Variable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == EFI_VARIABLE_HARDWARE_ERROR_RECORD) {
1204           mVariableModuleGlobal->HwErrVariableTotalSize += VariableSize;
1205         } else if ((Variable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) != EFI_VARIABLE_HARDWARE_ERROR_RECORD) {
1206           mVariableModuleGlobal->CommonVariableTotalSize += VariableSize;
1207           if (IsUserVariable (Variable)) {
1208             mVariableModuleGlobal->CommonUserVariableTotalSize += VariableSize;
1209           }
1210         }
1211 
1212         Variable = NextVariable;
1213       }
1214       *LastVariableOffset = (UINTN) Variable - (UINTN) VariableBase;
1215     }
1216   }
1217 
1218 Done:
1219   if (IsVolatile || mVariableModuleGlobal->VariableGlobal.EmuNvMode) {
1220     FreePool (ValidBuffer);
1221   } else {
1222     //
1223     // For NV variable reclaim, we use mNvVariableCache as the buffer, so copy the data back.
1224     //
1225     CopyMem (mNvVariableCache, (UINT8 *)(UINTN)VariableBase, VariableStoreHeader->Size);
1226   }
1227 
1228   return Status;
1229 }
1230 
1231 /**
1232   Find the variable in the specified variable store.
1233 
1234   @param[in]       VariableName        Name of the variable to be found
1235   @param[in]       VendorGuid          Vendor GUID to be found.
1236   @param[in]       IgnoreRtCheck       Ignore EFI_VARIABLE_RUNTIME_ACCESS attribute
1237                                        check at runtime when searching variable.
1238   @param[in, out]  PtrTrack            Variable Track Pointer structure that contains Variable Information.
1239 
1240   @retval          EFI_SUCCESS         Variable found successfully
1241   @retval          EFI_NOT_FOUND       Variable not found
1242 **/
1243 EFI_STATUS
FindVariableEx(IN CHAR16 * VariableName,IN EFI_GUID * VendorGuid,IN BOOLEAN IgnoreRtCheck,IN OUT VARIABLE_POINTER_TRACK * PtrTrack)1244 FindVariableEx (
1245   IN     CHAR16                  *VariableName,
1246   IN     EFI_GUID                *VendorGuid,
1247   IN     BOOLEAN                 IgnoreRtCheck,
1248   IN OUT VARIABLE_POINTER_TRACK  *PtrTrack
1249   )
1250 {
1251   VARIABLE_HEADER                *InDeletedVariable;
1252   VOID                           *Point;
1253 
1254   PtrTrack->InDeletedTransitionPtr = NULL;
1255 
1256   //
1257   // Find the variable by walk through HOB, volatile and non-volatile variable store.
1258   //
1259   InDeletedVariable  = NULL;
1260 
1261   for ( PtrTrack->CurrPtr = PtrTrack->StartPtr
1262       ; IsValidVariableHeader (PtrTrack->CurrPtr, PtrTrack->EndPtr)
1263       ; PtrTrack->CurrPtr = GetNextVariablePtr (PtrTrack->CurrPtr)
1264       ) {
1265     if (PtrTrack->CurrPtr->State == VAR_ADDED ||
1266         PtrTrack->CurrPtr->State == (VAR_IN_DELETED_TRANSITION & VAR_ADDED)
1267        ) {
1268       if (IgnoreRtCheck || !AtRuntime () || ((PtrTrack->CurrPtr->Attributes & EFI_VARIABLE_RUNTIME_ACCESS) != 0)) {
1269         if (VariableName[0] == 0) {
1270           if (PtrTrack->CurrPtr->State == (VAR_IN_DELETED_TRANSITION & VAR_ADDED)) {
1271             InDeletedVariable   = PtrTrack->CurrPtr;
1272           } else {
1273             PtrTrack->InDeletedTransitionPtr = InDeletedVariable;
1274             return EFI_SUCCESS;
1275           }
1276         } else {
1277           if (CompareGuid (VendorGuid, GetVendorGuidPtr (PtrTrack->CurrPtr))) {
1278             Point = (VOID *) GetVariableNamePtr (PtrTrack->CurrPtr);
1279 
1280             ASSERT (NameSizeOfVariable (PtrTrack->CurrPtr) != 0);
1281             if (CompareMem (VariableName, Point, NameSizeOfVariable (PtrTrack->CurrPtr)) == 0) {
1282               if (PtrTrack->CurrPtr->State == (VAR_IN_DELETED_TRANSITION & VAR_ADDED)) {
1283                 InDeletedVariable     = PtrTrack->CurrPtr;
1284               } else {
1285                 PtrTrack->InDeletedTransitionPtr = InDeletedVariable;
1286                 return EFI_SUCCESS;
1287               }
1288             }
1289           }
1290         }
1291       }
1292     }
1293   }
1294 
1295   PtrTrack->CurrPtr = InDeletedVariable;
1296   return (PtrTrack->CurrPtr  == NULL) ? EFI_NOT_FOUND : EFI_SUCCESS;
1297 }
1298 
1299 
1300 /**
1301   Finds variable in storage blocks of volatile and non-volatile storage areas.
1302 
1303   This code finds variable in storage blocks of volatile and non-volatile storage areas.
1304   If VariableName is an empty string, then we just return the first
1305   qualified variable without comparing VariableName and VendorGuid.
1306   If IgnoreRtCheck is TRUE, then we ignore the EFI_VARIABLE_RUNTIME_ACCESS attribute check
1307   at runtime when searching existing variable, only VariableName and VendorGuid are compared.
1308   Otherwise, variables without EFI_VARIABLE_RUNTIME_ACCESS are not visible at runtime.
1309 
1310   @param[in]   VariableName           Name of the variable to be found.
1311   @param[in]   VendorGuid             Vendor GUID to be found.
1312   @param[out]  PtrTrack               VARIABLE_POINTER_TRACK structure for output,
1313                                       including the range searched and the target position.
1314   @param[in]   Global                 Pointer to VARIABLE_GLOBAL structure, including
1315                                       base of volatile variable storage area, base of
1316                                       NV variable storage area, and a lock.
1317   @param[in]   IgnoreRtCheck          Ignore EFI_VARIABLE_RUNTIME_ACCESS attribute
1318                                       check at runtime when searching variable.
1319 
1320   @retval EFI_INVALID_PARAMETER       If VariableName is not an empty string, while
1321                                       VendorGuid is NULL.
1322   @retval EFI_SUCCESS                 Variable successfully found.
1323   @retval EFI_NOT_FOUND               Variable not found
1324 
1325 **/
1326 EFI_STATUS
FindVariable(IN CHAR16 * VariableName,IN EFI_GUID * VendorGuid,OUT VARIABLE_POINTER_TRACK * PtrTrack,IN VARIABLE_GLOBAL * Global,IN BOOLEAN IgnoreRtCheck)1327 FindVariable (
1328   IN  CHAR16                  *VariableName,
1329   IN  EFI_GUID                *VendorGuid,
1330   OUT VARIABLE_POINTER_TRACK  *PtrTrack,
1331   IN  VARIABLE_GLOBAL         *Global,
1332   IN  BOOLEAN                 IgnoreRtCheck
1333   )
1334 {
1335   EFI_STATUS              Status;
1336   VARIABLE_STORE_HEADER   *VariableStoreHeader[VariableStoreTypeMax];
1337   VARIABLE_STORE_TYPE     Type;
1338 
1339   if (VariableName[0] != 0 && VendorGuid == NULL) {
1340     return EFI_INVALID_PARAMETER;
1341   }
1342 
1343   //
1344   // 0: Volatile, 1: HOB, 2: Non-Volatile.
1345   // The index and attributes mapping must be kept in this order as RuntimeServiceGetNextVariableName
1346   // make use of this mapping to implement search algorithm.
1347   //
1348   VariableStoreHeader[VariableStoreTypeVolatile] = (VARIABLE_STORE_HEADER *) (UINTN) Global->VolatileVariableBase;
1349   VariableStoreHeader[VariableStoreTypeHob]      = (VARIABLE_STORE_HEADER *) (UINTN) Global->HobVariableBase;
1350   VariableStoreHeader[VariableStoreTypeNv]       = mNvVariableCache;
1351 
1352   //
1353   // Find the variable by walk through HOB, volatile and non-volatile variable store.
1354   //
1355   for (Type = (VARIABLE_STORE_TYPE) 0; Type < VariableStoreTypeMax; Type++) {
1356     if (VariableStoreHeader[Type] == NULL) {
1357       continue;
1358     }
1359 
1360     PtrTrack->StartPtr = GetStartPointer (VariableStoreHeader[Type]);
1361     PtrTrack->EndPtr   = GetEndPointer   (VariableStoreHeader[Type]);
1362     PtrTrack->Volatile = (BOOLEAN) (Type == VariableStoreTypeVolatile);
1363 
1364     Status = FindVariableEx (VariableName, VendorGuid, IgnoreRtCheck, PtrTrack);
1365     if (!EFI_ERROR (Status)) {
1366       return Status;
1367     }
1368   }
1369   return EFI_NOT_FOUND;
1370 }
1371 
1372 /**
1373   Get index from supported language codes according to language string.
1374 
1375   This code is used to get corresponding index in supported language codes. It can handle
1376   RFC4646 and ISO639 language tags.
1377   In ISO639 language tags, take 3-characters as a delimitation to find matched string and calculate the index.
1378   In RFC4646 language tags, take semicolon as a delimitation to find matched string and calculate the index.
1379 
1380   For example:
1381     SupportedLang  = "engfraengfra"
1382     Lang           = "eng"
1383     Iso639Language = TRUE
1384   The return value is "0".
1385   Another example:
1386     SupportedLang  = "en;fr;en-US;fr-FR"
1387     Lang           = "fr-FR"
1388     Iso639Language = FALSE
1389   The return value is "3".
1390 
1391   @param  SupportedLang               Platform supported language codes.
1392   @param  Lang                        Configured language.
1393   @param  Iso639Language              A bool value to signify if the handler is operated on ISO639 or RFC4646.
1394 
1395   @retval The index of language in the language codes.
1396 
1397 **/
1398 UINTN
GetIndexFromSupportedLangCodes(IN CHAR8 * SupportedLang,IN CHAR8 * Lang,IN BOOLEAN Iso639Language)1399 GetIndexFromSupportedLangCodes(
1400   IN  CHAR8            *SupportedLang,
1401   IN  CHAR8            *Lang,
1402   IN  BOOLEAN          Iso639Language
1403   )
1404 {
1405   UINTN    Index;
1406   UINTN    CompareLength;
1407   UINTN    LanguageLength;
1408 
1409   if (Iso639Language) {
1410     CompareLength = ISO_639_2_ENTRY_SIZE;
1411     for (Index = 0; Index < AsciiStrLen (SupportedLang); Index += CompareLength) {
1412       if (AsciiStrnCmp (Lang, SupportedLang + Index, CompareLength) == 0) {
1413         //
1414         // Successfully find the index of Lang string in SupportedLang string.
1415         //
1416         Index = Index / CompareLength;
1417         return Index;
1418       }
1419     }
1420     ASSERT (FALSE);
1421     return 0;
1422   } else {
1423     //
1424     // Compare RFC4646 language code
1425     //
1426     Index = 0;
1427     for (LanguageLength = 0; Lang[LanguageLength] != '\0'; LanguageLength++);
1428 
1429     for (Index = 0; *SupportedLang != '\0'; Index++, SupportedLang += CompareLength) {
1430       //
1431       // Skip ';' characters in SupportedLang
1432       //
1433       for (; *SupportedLang != '\0' && *SupportedLang == ';'; SupportedLang++);
1434       //
1435       // Determine the length of the next language code in SupportedLang
1436       //
1437       for (CompareLength = 0; SupportedLang[CompareLength] != '\0' && SupportedLang[CompareLength] != ';'; CompareLength++);
1438 
1439       if ((CompareLength == LanguageLength) &&
1440           (AsciiStrnCmp (Lang, SupportedLang, CompareLength) == 0)) {
1441         //
1442         // Successfully find the index of Lang string in SupportedLang string.
1443         //
1444         return Index;
1445       }
1446     }
1447     ASSERT (FALSE);
1448     return 0;
1449   }
1450 }
1451 
1452 /**
1453   Get language string from supported language codes according to index.
1454 
1455   This code is used to get corresponding language strings in supported language codes. It can handle
1456   RFC4646 and ISO639 language tags.
1457   In ISO639 language tags, take 3-characters as a delimitation. Find language string according to the index.
1458   In RFC4646 language tags, take semicolon as a delimitation. Find language string according to the index.
1459 
1460   For example:
1461     SupportedLang  = "engfraengfra"
1462     Index          = "1"
1463     Iso639Language = TRUE
1464   The return value is "fra".
1465   Another example:
1466     SupportedLang  = "en;fr;en-US;fr-FR"
1467     Index          = "1"
1468     Iso639Language = FALSE
1469   The return value is "fr".
1470 
1471   @param  SupportedLang               Platform supported language codes.
1472   @param  Index                       The index in supported language codes.
1473   @param  Iso639Language              A bool value to signify if the handler is operated on ISO639 or RFC4646.
1474 
1475   @retval The language string in the language codes.
1476 
1477 **/
1478 CHAR8 *
GetLangFromSupportedLangCodes(IN CHAR8 * SupportedLang,IN UINTN Index,IN BOOLEAN Iso639Language)1479 GetLangFromSupportedLangCodes (
1480   IN  CHAR8            *SupportedLang,
1481   IN  UINTN            Index,
1482   IN  BOOLEAN          Iso639Language
1483 )
1484 {
1485   UINTN    SubIndex;
1486   UINTN    CompareLength;
1487   CHAR8    *Supported;
1488 
1489   SubIndex  = 0;
1490   Supported = SupportedLang;
1491   if (Iso639Language) {
1492     //
1493     // According to the index of Lang string in SupportedLang string to get the language.
1494     // This code will be invoked in RUNTIME, therefore there is not a memory allocate/free operation.
1495     // In driver entry, it pre-allocates a runtime attribute memory to accommodate this string.
1496     //
1497     CompareLength = ISO_639_2_ENTRY_SIZE;
1498     mVariableModuleGlobal->Lang[CompareLength] = '\0';
1499     return CopyMem (mVariableModuleGlobal->Lang, SupportedLang + Index * CompareLength, CompareLength);
1500 
1501   } else {
1502     while (TRUE) {
1503       //
1504       // Take semicolon as delimitation, sequentially traverse supported language codes.
1505       //
1506       for (CompareLength = 0; *Supported != ';' && *Supported != '\0'; CompareLength++) {
1507         Supported++;
1508       }
1509       if ((*Supported == '\0') && (SubIndex != Index)) {
1510         //
1511         // Have completed the traverse, but not find corrsponding string.
1512         // This case is not allowed to happen.
1513         //
1514         ASSERT(FALSE);
1515         return NULL;
1516       }
1517       if (SubIndex == Index) {
1518         //
1519         // According to the index of Lang string in SupportedLang string to get the language.
1520         // As this code will be invoked in RUNTIME, therefore there is not memory allocate/free operation.
1521         // In driver entry, it pre-allocates a runtime attribute memory to accommodate this string.
1522         //
1523         mVariableModuleGlobal->PlatformLang[CompareLength] = '\0';
1524         return CopyMem (mVariableModuleGlobal->PlatformLang, Supported - CompareLength, CompareLength);
1525       }
1526       SubIndex++;
1527 
1528       //
1529       // Skip ';' characters in Supported
1530       //
1531       for (; *Supported != '\0' && *Supported == ';'; Supported++);
1532     }
1533   }
1534 }
1535 
1536 /**
1537   Returns a pointer to an allocated buffer that contains the best matching language
1538   from a set of supported languages.
1539 
1540   This function supports both ISO 639-2 and RFC 4646 language codes, but language
1541   code types may not be mixed in a single call to this function. This function
1542   supports a variable argument list that allows the caller to pass in a prioritized
1543   list of language codes to test against all the language codes in SupportedLanguages.
1544 
1545   If SupportedLanguages is NULL, then ASSERT().
1546 
1547   @param[in]  SupportedLanguages  A pointer to a Null-terminated ASCII string that
1548                                   contains a set of language codes in the format
1549                                   specified by Iso639Language.
1550   @param[in]  Iso639Language      If not zero, then all language codes are assumed to be
1551                                   in ISO 639-2 format.  If zero, then all language
1552                                   codes are assumed to be in RFC 4646 language format
1553   @param[in]  ...                 A variable argument list that contains pointers to
1554                                   Null-terminated ASCII strings that contain one or more
1555                                   language codes in the format specified by Iso639Language.
1556                                   The first language code from each of these language
1557                                   code lists is used to determine if it is an exact or
1558                                   close match to any of the language codes in
1559                                   SupportedLanguages.  Close matches only apply to RFC 4646
1560                                   language codes, and the matching algorithm from RFC 4647
1561                                   is used to determine if a close match is present.  If
1562                                   an exact or close match is found, then the matching
1563                                   language code from SupportedLanguages is returned.  If
1564                                   no matches are found, then the next variable argument
1565                                   parameter is evaluated.  The variable argument list
1566                                   is terminated by a NULL.
1567 
1568   @retval NULL   The best matching language could not be found in SupportedLanguages.
1569   @retval NULL   There are not enough resources available to return the best matching
1570                  language.
1571   @retval Other  A pointer to a Null-terminated ASCII string that is the best matching
1572                  language in SupportedLanguages.
1573 
1574 **/
1575 CHAR8 *
1576 EFIAPI
VariableGetBestLanguage(IN CONST CHAR8 * SupportedLanguages,IN UINTN Iso639Language,...)1577 VariableGetBestLanguage (
1578   IN CONST CHAR8  *SupportedLanguages,
1579   IN UINTN        Iso639Language,
1580   ...
1581   )
1582 {
1583   VA_LIST      Args;
1584   CHAR8        *Language;
1585   UINTN        CompareLength;
1586   UINTN        LanguageLength;
1587   CONST CHAR8  *Supported;
1588   CHAR8        *Buffer;
1589 
1590   if (SupportedLanguages == NULL) {
1591     return NULL;
1592   }
1593 
1594   VA_START (Args, Iso639Language);
1595   while ((Language = VA_ARG (Args, CHAR8 *)) != NULL) {
1596     //
1597     // Default to ISO 639-2 mode
1598     //
1599     CompareLength  = 3;
1600     LanguageLength = MIN (3, AsciiStrLen (Language));
1601 
1602     //
1603     // If in RFC 4646 mode, then determine the length of the first RFC 4646 language code in Language
1604     //
1605     if (Iso639Language == 0) {
1606       for (LanguageLength = 0; Language[LanguageLength] != 0 && Language[LanguageLength] != ';'; LanguageLength++);
1607     }
1608 
1609     //
1610     // Trim back the length of Language used until it is empty
1611     //
1612     while (LanguageLength > 0) {
1613       //
1614       // Loop through all language codes in SupportedLanguages
1615       //
1616       for (Supported = SupportedLanguages; *Supported != '\0'; Supported += CompareLength) {
1617         //
1618         // In RFC 4646 mode, then Loop through all language codes in SupportedLanguages
1619         //
1620         if (Iso639Language == 0) {
1621           //
1622           // Skip ';' characters in Supported
1623           //
1624           for (; *Supported != '\0' && *Supported == ';'; Supported++);
1625           //
1626           // Determine the length of the next language code in Supported
1627           //
1628           for (CompareLength = 0; Supported[CompareLength] != 0 && Supported[CompareLength] != ';'; CompareLength++);
1629           //
1630           // If Language is longer than the Supported, then skip to the next language
1631           //
1632           if (LanguageLength > CompareLength) {
1633             continue;
1634           }
1635         }
1636         //
1637         // See if the first LanguageLength characters in Supported match Language
1638         //
1639         if (AsciiStrnCmp (Supported, Language, LanguageLength) == 0) {
1640           VA_END (Args);
1641 
1642           Buffer = (Iso639Language != 0) ? mVariableModuleGlobal->Lang : mVariableModuleGlobal->PlatformLang;
1643           Buffer[CompareLength] = '\0';
1644           return CopyMem (Buffer, Supported, CompareLength);
1645         }
1646       }
1647 
1648       if (Iso639Language != 0) {
1649         //
1650         // If ISO 639 mode, then each language can only be tested once
1651         //
1652         LanguageLength = 0;
1653       } else {
1654         //
1655         // If RFC 4646 mode, then trim Language from the right to the next '-' character
1656         //
1657         for (LanguageLength--; LanguageLength > 0 && Language[LanguageLength] != '-'; LanguageLength--);
1658       }
1659     }
1660   }
1661   VA_END (Args);
1662 
1663   //
1664   // No matches were found
1665   //
1666   return NULL;
1667 }
1668 
1669 /**
1670   This function is to check if the remaining variable space is enough to set
1671   all Variables from argument list successfully. The purpose of the check
1672   is to keep the consistency of the Variables to be in variable storage.
1673 
1674   Note: Variables are assumed to be in same storage.
1675   The set sequence of Variables will be same with the sequence of VariableEntry from argument list,
1676   so follow the argument sequence to check the Variables.
1677 
1678   @param[in] Attributes         Variable attributes for Variable entries.
1679   @param[in] Marker             VA_LIST style variable argument list.
1680                                 The variable argument list with type VARIABLE_ENTRY_CONSISTENCY *.
1681                                 A NULL terminates the list. The VariableSize of
1682                                 VARIABLE_ENTRY_CONSISTENCY is the variable data size as input.
1683                                 It will be changed to variable total size as output.
1684 
1685   @retval TRUE                  Have enough variable space to set the Variables successfully.
1686   @retval FALSE                 No enough variable space to set the Variables successfully.
1687 
1688 **/
1689 BOOLEAN
1690 EFIAPI
CheckRemainingSpaceForConsistencyInternal(IN UINT32 Attributes,IN VA_LIST Marker)1691 CheckRemainingSpaceForConsistencyInternal (
1692   IN UINT32                     Attributes,
1693   IN VA_LIST                    Marker
1694   )
1695 {
1696   EFI_STATUS                    Status;
1697   VA_LIST                       Args;
1698   VARIABLE_ENTRY_CONSISTENCY    *VariableEntry;
1699   UINT64                        MaximumVariableStorageSize;
1700   UINT64                        RemainingVariableStorageSize;
1701   UINT64                        MaximumVariableSize;
1702   UINTN                         TotalNeededSize;
1703   UINTN                         OriginalVarSize;
1704   VARIABLE_STORE_HEADER         *VariableStoreHeader;
1705   VARIABLE_POINTER_TRACK        VariablePtrTrack;
1706   VARIABLE_HEADER               *NextVariable;
1707   UINTN                         VarNameSize;
1708   UINTN                         VarDataSize;
1709 
1710   //
1711   // Non-Volatile related.
1712   //
1713   VariableStoreHeader = mNvVariableCache;
1714 
1715   Status = VariableServiceQueryVariableInfoInternal (
1716              Attributes,
1717              &MaximumVariableStorageSize,
1718              &RemainingVariableStorageSize,
1719              &MaximumVariableSize
1720              );
1721   ASSERT_EFI_ERROR (Status);
1722 
1723   TotalNeededSize = 0;
1724   VA_COPY (Args, Marker);
1725   VariableEntry = VA_ARG (Args, VARIABLE_ENTRY_CONSISTENCY *);
1726   while (VariableEntry != NULL) {
1727     //
1728     // Calculate variable total size.
1729     //
1730     VarNameSize  = StrSize (VariableEntry->Name);
1731     VarNameSize += GET_PAD_SIZE (VarNameSize);
1732     VarDataSize  = VariableEntry->VariableSize;
1733     VarDataSize += GET_PAD_SIZE (VarDataSize);
1734     VariableEntry->VariableSize = HEADER_ALIGN (GetVariableHeaderSize () + VarNameSize + VarDataSize);
1735 
1736     TotalNeededSize += VariableEntry->VariableSize;
1737     VariableEntry = VA_ARG (Args, VARIABLE_ENTRY_CONSISTENCY *);
1738   }
1739   VA_END  (Args);
1740 
1741   if (RemainingVariableStorageSize >= TotalNeededSize) {
1742     //
1743     // Already have enough space.
1744     //
1745     return TRUE;
1746   } else if (AtRuntime ()) {
1747     //
1748     // At runtime, no reclaim.
1749     // The original variable space of Variables can't be reused.
1750     //
1751     return FALSE;
1752   }
1753 
1754   VA_COPY (Args, Marker);
1755   VariableEntry = VA_ARG (Args, VARIABLE_ENTRY_CONSISTENCY *);
1756   while (VariableEntry != NULL) {
1757     //
1758     // Check if Variable[Index] has been present and get its size.
1759     //
1760     OriginalVarSize = 0;
1761     VariablePtrTrack.StartPtr = GetStartPointer (VariableStoreHeader);
1762     VariablePtrTrack.EndPtr   = GetEndPointer   (VariableStoreHeader);
1763     Status = FindVariableEx (
1764                VariableEntry->Name,
1765                VariableEntry->Guid,
1766                FALSE,
1767                &VariablePtrTrack
1768                );
1769     if (!EFI_ERROR (Status)) {
1770       //
1771       // Get size of Variable[Index].
1772       //
1773       NextVariable = GetNextVariablePtr (VariablePtrTrack.CurrPtr);
1774       OriginalVarSize = (UINTN) NextVariable - (UINTN) VariablePtrTrack.CurrPtr;
1775       //
1776       // Add the original size of Variable[Index] to remaining variable storage size.
1777       //
1778       RemainingVariableStorageSize += OriginalVarSize;
1779     }
1780     if (VariableEntry->VariableSize > RemainingVariableStorageSize) {
1781       //
1782       // No enough space for Variable[Index].
1783       //
1784       VA_END (Args);
1785       return FALSE;
1786     }
1787     //
1788     // Sub the (new) size of Variable[Index] from remaining variable storage size.
1789     //
1790     RemainingVariableStorageSize -= VariableEntry->VariableSize;
1791     VariableEntry = VA_ARG (Args, VARIABLE_ENTRY_CONSISTENCY *);
1792   }
1793   VA_END  (Args);
1794 
1795   return TRUE;
1796 }
1797 
1798 /**
1799   This function is to check if the remaining variable space is enough to set
1800   all Variables from argument list successfully. The purpose of the check
1801   is to keep the consistency of the Variables to be in variable storage.
1802 
1803   Note: Variables are assumed to be in same storage.
1804   The set sequence of Variables will be same with the sequence of VariableEntry from argument list,
1805   so follow the argument sequence to check the Variables.
1806 
1807   @param[in] Attributes         Variable attributes for Variable entries.
1808   @param ...                    The variable argument list with type VARIABLE_ENTRY_CONSISTENCY *.
1809                                 A NULL terminates the list. The VariableSize of
1810                                 VARIABLE_ENTRY_CONSISTENCY is the variable data size as input.
1811                                 It will be changed to variable total size as output.
1812 
1813   @retval TRUE                  Have enough variable space to set the Variables successfully.
1814   @retval FALSE                 No enough variable space to set the Variables successfully.
1815 
1816 **/
1817 BOOLEAN
1818 EFIAPI
CheckRemainingSpaceForConsistency(IN UINT32 Attributes,...)1819 CheckRemainingSpaceForConsistency (
1820   IN UINT32                     Attributes,
1821   ...
1822   )
1823 {
1824   VA_LIST Marker;
1825   BOOLEAN Return;
1826 
1827   VA_START (Marker, Attributes);
1828 
1829   Return = CheckRemainingSpaceForConsistencyInternal (Attributes, Marker);
1830 
1831   VA_END (Marker);
1832 
1833   return Return;
1834 }
1835 
1836 /**
1837   Hook the operations in PlatformLangCodes, LangCodes, PlatformLang and Lang.
1838 
1839   When setting Lang/LangCodes, simultaneously update PlatformLang/PlatformLangCodes.
1840 
1841   According to UEFI spec, PlatformLangCodes/LangCodes are only set once in firmware initialization,
1842   and are read-only. Therefore, in variable driver, only store the original value for other use.
1843 
1844   @param[in] VariableName       Name of variable.
1845 
1846   @param[in] Data               Variable data.
1847 
1848   @param[in] DataSize           Size of data. 0 means delete.
1849 
1850   @retval EFI_SUCCESS           The update operation is successful or ignored.
1851   @retval EFI_WRITE_PROTECTED   Update PlatformLangCodes/LangCodes at runtime.
1852   @retval EFI_OUT_OF_RESOURCES  No enough variable space to do the update operation.
1853   @retval Others                Other errors happened during the update operation.
1854 
1855 **/
1856 EFI_STATUS
AutoUpdateLangVariable(IN CHAR16 * VariableName,IN VOID * Data,IN UINTN DataSize)1857 AutoUpdateLangVariable (
1858   IN  CHAR16             *VariableName,
1859   IN  VOID               *Data,
1860   IN  UINTN              DataSize
1861   )
1862 {
1863   EFI_STATUS             Status;
1864   CHAR8                  *BestPlatformLang;
1865   CHAR8                  *BestLang;
1866   UINTN                  Index;
1867   UINT32                 Attributes;
1868   VARIABLE_POINTER_TRACK Variable;
1869   BOOLEAN                SetLanguageCodes;
1870   VARIABLE_ENTRY_CONSISTENCY VariableEntry[2];
1871 
1872   //
1873   // Don't do updates for delete operation
1874   //
1875   if (DataSize == 0) {
1876     return EFI_SUCCESS;
1877   }
1878 
1879   SetLanguageCodes = FALSE;
1880 
1881   if (StrCmp (VariableName, EFI_PLATFORM_LANG_CODES_VARIABLE_NAME) == 0) {
1882     //
1883     // PlatformLangCodes is a volatile variable, so it can not be updated at runtime.
1884     //
1885     if (AtRuntime ()) {
1886       return EFI_WRITE_PROTECTED;
1887     }
1888 
1889     SetLanguageCodes = TRUE;
1890 
1891     //
1892     // According to UEFI spec, PlatformLangCodes is only set once in firmware initialization, and is read-only
1893     // Therefore, in variable driver, only store the original value for other use.
1894     //
1895     if (mVariableModuleGlobal->PlatformLangCodes != NULL) {
1896       FreePool (mVariableModuleGlobal->PlatformLangCodes);
1897     }
1898     mVariableModuleGlobal->PlatformLangCodes = AllocateRuntimeCopyPool (DataSize, Data);
1899     ASSERT (mVariableModuleGlobal->PlatformLangCodes != NULL);
1900 
1901     //
1902     // PlatformLang holds a single language from PlatformLangCodes,
1903     // so the size of PlatformLangCodes is enough for the PlatformLang.
1904     //
1905     if (mVariableModuleGlobal->PlatformLang != NULL) {
1906       FreePool (mVariableModuleGlobal->PlatformLang);
1907     }
1908     mVariableModuleGlobal->PlatformLang = AllocateRuntimePool (DataSize);
1909     ASSERT (mVariableModuleGlobal->PlatformLang != NULL);
1910 
1911   } else if (StrCmp (VariableName, EFI_LANG_CODES_VARIABLE_NAME) == 0) {
1912     //
1913     // LangCodes is a volatile variable, so it can not be updated at runtime.
1914     //
1915     if (AtRuntime ()) {
1916       return EFI_WRITE_PROTECTED;
1917     }
1918 
1919     SetLanguageCodes = TRUE;
1920 
1921     //
1922     // According to UEFI spec, LangCodes is only set once in firmware initialization, and is read-only
1923     // Therefore, in variable driver, only store the original value for other use.
1924     //
1925     if (mVariableModuleGlobal->LangCodes != NULL) {
1926       FreePool (mVariableModuleGlobal->LangCodes);
1927     }
1928     mVariableModuleGlobal->LangCodes = AllocateRuntimeCopyPool (DataSize, Data);
1929     ASSERT (mVariableModuleGlobal->LangCodes != NULL);
1930   }
1931 
1932   if (SetLanguageCodes
1933       && (mVariableModuleGlobal->PlatformLangCodes != NULL)
1934       && (mVariableModuleGlobal->LangCodes != NULL)) {
1935     //
1936     // Update Lang if PlatformLang is already set
1937     // Update PlatformLang if Lang is already set
1938     //
1939     Status = FindVariable (EFI_PLATFORM_LANG_VARIABLE_NAME, &gEfiGlobalVariableGuid, &Variable, &mVariableModuleGlobal->VariableGlobal, FALSE);
1940     if (!EFI_ERROR (Status)) {
1941       //
1942       // Update Lang
1943       //
1944       VariableName = EFI_PLATFORM_LANG_VARIABLE_NAME;
1945       Data         = GetVariableDataPtr (Variable.CurrPtr);
1946       DataSize     = DataSizeOfVariable (Variable.CurrPtr);
1947     } else {
1948       Status = FindVariable (EFI_LANG_VARIABLE_NAME, &gEfiGlobalVariableGuid, &Variable, &mVariableModuleGlobal->VariableGlobal, FALSE);
1949       if (!EFI_ERROR (Status)) {
1950         //
1951         // Update PlatformLang
1952         //
1953         VariableName = EFI_LANG_VARIABLE_NAME;
1954         Data         = GetVariableDataPtr (Variable.CurrPtr);
1955         DataSize     = DataSizeOfVariable (Variable.CurrPtr);
1956       } else {
1957         //
1958         // Neither PlatformLang nor Lang is set, directly return
1959         //
1960         return EFI_SUCCESS;
1961       }
1962     }
1963   }
1964 
1965   Status = EFI_SUCCESS;
1966 
1967   //
1968   // According to UEFI spec, "Lang" and "PlatformLang" is NV|BS|RT attributions.
1969   //
1970   Attributes = EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS;
1971 
1972   if (StrCmp (VariableName, EFI_PLATFORM_LANG_VARIABLE_NAME) == 0) {
1973     //
1974     // Update Lang when PlatformLangCodes/LangCodes were set.
1975     //
1976     if ((mVariableModuleGlobal->PlatformLangCodes != NULL) && (mVariableModuleGlobal->LangCodes != NULL)) {
1977       //
1978       // When setting PlatformLang, firstly get most matched language string from supported language codes.
1979       //
1980       BestPlatformLang = VariableGetBestLanguage (mVariableModuleGlobal->PlatformLangCodes, FALSE, Data, NULL);
1981       if (BestPlatformLang != NULL) {
1982         //
1983         // Get the corresponding index in language codes.
1984         //
1985         Index = GetIndexFromSupportedLangCodes (mVariableModuleGlobal->PlatformLangCodes, BestPlatformLang, FALSE);
1986 
1987         //
1988         // Get the corresponding ISO639 language tag according to RFC4646 language tag.
1989         //
1990         BestLang = GetLangFromSupportedLangCodes (mVariableModuleGlobal->LangCodes, Index, TRUE);
1991 
1992         //
1993         // Check the variable space for both Lang and PlatformLang variable.
1994         //
1995         VariableEntry[0].VariableSize = ISO_639_2_ENTRY_SIZE + 1;
1996         VariableEntry[0].Guid = &gEfiGlobalVariableGuid;
1997         VariableEntry[0].Name = EFI_LANG_VARIABLE_NAME;
1998 
1999         VariableEntry[1].VariableSize = AsciiStrSize (BestPlatformLang);
2000         VariableEntry[1].Guid = &gEfiGlobalVariableGuid;
2001         VariableEntry[1].Name = EFI_PLATFORM_LANG_VARIABLE_NAME;
2002         if (!CheckRemainingSpaceForConsistency (VARIABLE_ATTRIBUTE_NV_BS_RT, &VariableEntry[0], &VariableEntry[1], NULL)) {
2003           //
2004           // No enough variable space to set both Lang and PlatformLang successfully.
2005           //
2006           Status = EFI_OUT_OF_RESOURCES;
2007         } else {
2008           //
2009           // Successfully convert PlatformLang to Lang, and set the BestLang value into Lang variable simultaneously.
2010           //
2011           FindVariable (EFI_LANG_VARIABLE_NAME, &gEfiGlobalVariableGuid, &Variable, &mVariableModuleGlobal->VariableGlobal, FALSE);
2012 
2013           Status = UpdateVariable (EFI_LANG_VARIABLE_NAME, &gEfiGlobalVariableGuid, BestLang,
2014                                    ISO_639_2_ENTRY_SIZE + 1, Attributes, 0, 0, &Variable, NULL);
2015         }
2016 
2017         DEBUG ((EFI_D_INFO, "Variable Driver Auto Update PlatformLang, PlatformLang:%a, Lang:%a Status: %r\n", BestPlatformLang, BestLang, Status));
2018       }
2019     }
2020 
2021   } else if (StrCmp (VariableName, EFI_LANG_VARIABLE_NAME) == 0) {
2022     //
2023     // Update PlatformLang when PlatformLangCodes/LangCodes were set.
2024     //
2025     if ((mVariableModuleGlobal->PlatformLangCodes != NULL) && (mVariableModuleGlobal->LangCodes != NULL)) {
2026       //
2027       // When setting Lang, firstly get most matched language string from supported language codes.
2028       //
2029       BestLang = VariableGetBestLanguage (mVariableModuleGlobal->LangCodes, TRUE, Data, NULL);
2030       if (BestLang != NULL) {
2031         //
2032         // Get the corresponding index in language codes.
2033         //
2034         Index = GetIndexFromSupportedLangCodes (mVariableModuleGlobal->LangCodes, BestLang, TRUE);
2035 
2036         //
2037         // Get the corresponding RFC4646 language tag according to ISO639 language tag.
2038         //
2039         BestPlatformLang = GetLangFromSupportedLangCodes (mVariableModuleGlobal->PlatformLangCodes, Index, FALSE);
2040 
2041         //
2042         // Check the variable space for both PlatformLang and Lang variable.
2043         //
2044         VariableEntry[0].VariableSize = AsciiStrSize (BestPlatformLang);
2045         VariableEntry[0].Guid = &gEfiGlobalVariableGuid;
2046         VariableEntry[0].Name = EFI_PLATFORM_LANG_VARIABLE_NAME;
2047 
2048         VariableEntry[1].VariableSize = ISO_639_2_ENTRY_SIZE + 1;
2049         VariableEntry[1].Guid = &gEfiGlobalVariableGuid;
2050         VariableEntry[1].Name = EFI_LANG_VARIABLE_NAME;
2051         if (!CheckRemainingSpaceForConsistency (VARIABLE_ATTRIBUTE_NV_BS_RT, &VariableEntry[0], &VariableEntry[1], NULL)) {
2052           //
2053           // No enough variable space to set both PlatformLang and Lang successfully.
2054           //
2055           Status = EFI_OUT_OF_RESOURCES;
2056         } else {
2057           //
2058           // Successfully convert Lang to PlatformLang, and set the BestPlatformLang value into PlatformLang variable simultaneously.
2059           //
2060           FindVariable (EFI_PLATFORM_LANG_VARIABLE_NAME, &gEfiGlobalVariableGuid, &Variable, &mVariableModuleGlobal->VariableGlobal, FALSE);
2061 
2062           Status = UpdateVariable (EFI_PLATFORM_LANG_VARIABLE_NAME, &gEfiGlobalVariableGuid, BestPlatformLang,
2063                                    AsciiStrSize (BestPlatformLang), Attributes, 0, 0, &Variable, NULL);
2064         }
2065 
2066         DEBUG ((EFI_D_INFO, "Variable Driver Auto Update Lang, Lang:%a, PlatformLang:%a Status: %r\n", BestLang, BestPlatformLang, Status));
2067       }
2068     }
2069   }
2070 
2071   if (SetLanguageCodes) {
2072     //
2073     // Continue to set PlatformLangCodes or LangCodes.
2074     //
2075     return EFI_SUCCESS;
2076   } else {
2077     return Status;
2078   }
2079 }
2080 
2081 /**
2082   Compare two EFI_TIME data.
2083 
2084 
2085   @param FirstTime           A pointer to the first EFI_TIME data.
2086   @param SecondTime          A pointer to the second EFI_TIME data.
2087 
2088   @retval  TRUE              The FirstTime is not later than the SecondTime.
2089   @retval  FALSE             The FirstTime is later than the SecondTime.
2090 
2091 **/
2092 BOOLEAN
VariableCompareTimeStampInternal(IN EFI_TIME * FirstTime,IN EFI_TIME * SecondTime)2093 VariableCompareTimeStampInternal (
2094   IN EFI_TIME               *FirstTime,
2095   IN EFI_TIME               *SecondTime
2096   )
2097 {
2098   if (FirstTime->Year != SecondTime->Year) {
2099     return (BOOLEAN) (FirstTime->Year < SecondTime->Year);
2100   } else if (FirstTime->Month != SecondTime->Month) {
2101     return (BOOLEAN) (FirstTime->Month < SecondTime->Month);
2102   } else if (FirstTime->Day != SecondTime->Day) {
2103     return (BOOLEAN) (FirstTime->Day < SecondTime->Day);
2104   } else if (FirstTime->Hour != SecondTime->Hour) {
2105     return (BOOLEAN) (FirstTime->Hour < SecondTime->Hour);
2106   } else if (FirstTime->Minute != SecondTime->Minute) {
2107     return (BOOLEAN) (FirstTime->Minute < SecondTime->Minute);
2108   }
2109 
2110   return (BOOLEAN) (FirstTime->Second <= SecondTime->Second);
2111 }
2112 
2113 /**
2114   Update the variable region with Variable information. If EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS is set,
2115   index of associated public key is needed.
2116 
2117   @param[in] VariableName       Name of variable.
2118   @param[in] VendorGuid         Guid of variable.
2119   @param[in] Data               Variable data.
2120   @param[in] DataSize           Size of data. 0 means delete.
2121   @param[in] Attributes         Attributes of the variable.
2122   @param[in] KeyIndex           Index of associated public key.
2123   @param[in] MonotonicCount     Value of associated monotonic count.
2124   @param[in, out] CacheVariable The variable information which is used to keep track of variable usage.
2125   @param[in] TimeStamp          Value of associated TimeStamp.
2126 
2127   @retval EFI_SUCCESS           The update operation is success.
2128   @retval EFI_OUT_OF_RESOURCES  Variable region is full, can not write other data into this region.
2129 
2130 **/
2131 EFI_STATUS
UpdateVariable(IN CHAR16 * VariableName,IN EFI_GUID * VendorGuid,IN VOID * Data,IN UINTN DataSize,IN UINT32 Attributes OPTIONAL,IN UINT32 KeyIndex OPTIONAL,IN UINT64 MonotonicCount OPTIONAL,IN OUT VARIABLE_POINTER_TRACK * CacheVariable,IN EFI_TIME * TimeStamp OPTIONAL)2132 UpdateVariable (
2133   IN      CHAR16                      *VariableName,
2134   IN      EFI_GUID                    *VendorGuid,
2135   IN      VOID                        *Data,
2136   IN      UINTN                       DataSize,
2137   IN      UINT32                      Attributes      OPTIONAL,
2138   IN      UINT32                      KeyIndex        OPTIONAL,
2139   IN      UINT64                      MonotonicCount  OPTIONAL,
2140   IN OUT  VARIABLE_POINTER_TRACK      *CacheVariable,
2141   IN      EFI_TIME                    *TimeStamp      OPTIONAL
2142   )
2143 {
2144   EFI_STATUS                          Status;
2145   VARIABLE_HEADER                     *NextVariable;
2146   UINTN                               ScratchSize;
2147   UINTN                               MaxDataSize;
2148   UINTN                               VarNameOffset;
2149   UINTN                               VarDataOffset;
2150   UINTN                               VarNameSize;
2151   UINTN                               VarSize;
2152   BOOLEAN                             Volatile;
2153   EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL  *Fvb;
2154   UINT8                               State;
2155   VARIABLE_POINTER_TRACK              *Variable;
2156   VARIABLE_POINTER_TRACK              NvVariable;
2157   VARIABLE_STORE_HEADER               *VariableStoreHeader;
2158   UINT8                               *BufferForMerge;
2159   UINTN                               MergedBufSize;
2160   BOOLEAN                             DataReady;
2161   UINTN                               DataOffset;
2162   BOOLEAN                             IsCommonVariable;
2163   BOOLEAN                             IsCommonUserVariable;
2164   AUTHENTICATED_VARIABLE_HEADER       *AuthVariable;
2165 
2166   if (mVariableModuleGlobal->FvbInstance == NULL && !mVariableModuleGlobal->VariableGlobal.EmuNvMode) {
2167     //
2168     // The FVB protocol is not ready, so the EFI_VARIABLE_WRITE_ARCH_PROTOCOL is not installed.
2169     //
2170     if ((Attributes & EFI_VARIABLE_NON_VOLATILE) != 0) {
2171       //
2172       // Trying to update NV variable prior to the installation of EFI_VARIABLE_WRITE_ARCH_PROTOCOL
2173       //
2174       DEBUG ((EFI_D_ERROR, "Update NV variable before EFI_VARIABLE_WRITE_ARCH_PROTOCOL ready - %r\n", EFI_NOT_AVAILABLE_YET));
2175       return EFI_NOT_AVAILABLE_YET;
2176     } else if ((Attributes & VARIABLE_ATTRIBUTE_AT_AW) != 0) {
2177       //
2178       // Trying to update volatile authenticated variable prior to the installation of EFI_VARIABLE_WRITE_ARCH_PROTOCOL
2179       // The authenticated variable perhaps is not initialized, just return here.
2180       //
2181       DEBUG ((EFI_D_ERROR, "Update AUTH variable before EFI_VARIABLE_WRITE_ARCH_PROTOCOL ready - %r\n", EFI_NOT_AVAILABLE_YET));
2182       return EFI_NOT_AVAILABLE_YET;
2183     }
2184   }
2185 
2186   //
2187   // Check if CacheVariable points to the variable in variable HOB.
2188   // If yes, let CacheVariable points to the variable in NV variable cache.
2189   //
2190   if ((CacheVariable->CurrPtr != NULL) &&
2191       (mVariableModuleGlobal->VariableGlobal.HobVariableBase != 0) &&
2192       (CacheVariable->StartPtr == GetStartPointer ((VARIABLE_STORE_HEADER *) (UINTN) mVariableModuleGlobal->VariableGlobal.HobVariableBase))
2193      ) {
2194     CacheVariable->StartPtr = GetStartPointer (mNvVariableCache);
2195     CacheVariable->EndPtr   = GetEndPointer   (mNvVariableCache);
2196     CacheVariable->Volatile = FALSE;
2197     Status = FindVariableEx (VariableName, VendorGuid, FALSE, CacheVariable);
2198     if (CacheVariable->CurrPtr == NULL || EFI_ERROR (Status)) {
2199       //
2200       // There is no matched variable in NV variable cache.
2201       //
2202       if ((((Attributes & EFI_VARIABLE_APPEND_WRITE) == 0) && (DataSize == 0)) || (Attributes == 0)) {
2203         //
2204         // It is to delete variable,
2205         // go to delete this variable in variable HOB and
2206         // try to flush other variables from HOB to flash.
2207         //
2208         UpdateVariableInfo (VariableName, VendorGuid, FALSE, FALSE, FALSE, TRUE, FALSE);
2209         FlushHobVariableToFlash (VariableName, VendorGuid);
2210         return EFI_SUCCESS;
2211       }
2212     }
2213   }
2214 
2215   if ((CacheVariable->CurrPtr == NULL) || CacheVariable->Volatile) {
2216     Variable = CacheVariable;
2217   } else {
2218     //
2219     // Update/Delete existing NV variable.
2220     // CacheVariable points to the variable in the memory copy of Flash area
2221     // Now let Variable points to the same variable in Flash area.
2222     //
2223     VariableStoreHeader  = (VARIABLE_STORE_HEADER *) ((UINTN) mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase);
2224     Variable = &NvVariable;
2225     Variable->StartPtr = GetStartPointer (VariableStoreHeader);
2226     Variable->EndPtr   = (VARIABLE_HEADER *)((UINTN)Variable->StartPtr + ((UINTN)CacheVariable->EndPtr - (UINTN)CacheVariable->StartPtr));
2227 
2228     Variable->CurrPtr  = (VARIABLE_HEADER *)((UINTN)Variable->StartPtr + ((UINTN)CacheVariable->CurrPtr - (UINTN)CacheVariable->StartPtr));
2229     if (CacheVariable->InDeletedTransitionPtr != NULL) {
2230       Variable->InDeletedTransitionPtr = (VARIABLE_HEADER *)((UINTN)Variable->StartPtr + ((UINTN)CacheVariable->InDeletedTransitionPtr - (UINTN)CacheVariable->StartPtr));
2231     } else {
2232       Variable->InDeletedTransitionPtr = NULL;
2233     }
2234     Variable->Volatile = FALSE;
2235   }
2236 
2237   Fvb       = mVariableModuleGlobal->FvbInstance;
2238 
2239   //
2240   // Tricky part: Use scratch data area at the end of volatile variable store
2241   // as a temporary storage.
2242   //
2243   NextVariable = GetEndPointer ((VARIABLE_STORE_HEADER *) ((UINTN) mVariableModuleGlobal->VariableGlobal.VolatileVariableBase));
2244   ScratchSize = mVariableModuleGlobal->ScratchBufferSize;
2245   SetMem (NextVariable, ScratchSize, 0xff);
2246   DataReady = FALSE;
2247 
2248   if (Variable->CurrPtr != NULL) {
2249     //
2250     // Update/Delete existing variable.
2251     //
2252     if (AtRuntime ()) {
2253       //
2254       // If AtRuntime and the variable is Volatile and Runtime Access,
2255       // the volatile is ReadOnly, and SetVariable should be aborted and
2256       // return EFI_WRITE_PROTECTED.
2257       //
2258       if (Variable->Volatile) {
2259         Status = EFI_WRITE_PROTECTED;
2260         goto Done;
2261       }
2262       //
2263       // Only variable that have NV attributes can be updated/deleted in Runtime.
2264       //
2265       if ((CacheVariable->CurrPtr->Attributes & EFI_VARIABLE_NON_VOLATILE) == 0) {
2266         Status = EFI_INVALID_PARAMETER;
2267         goto Done;
2268       }
2269 
2270       //
2271       // Only variable that have RT attributes can be updated/deleted in Runtime.
2272       //
2273       if ((CacheVariable->CurrPtr->Attributes & EFI_VARIABLE_RUNTIME_ACCESS) == 0) {
2274         Status = EFI_INVALID_PARAMETER;
2275         goto Done;
2276       }
2277     }
2278 
2279     //
2280     // Setting a data variable with no access, or zero DataSize attributes
2281     // causes it to be deleted.
2282     // When the EFI_VARIABLE_APPEND_WRITE attribute is set, DataSize of zero will
2283     // not delete the variable.
2284     //
2285     if ((((Attributes & EFI_VARIABLE_APPEND_WRITE) == 0) && (DataSize == 0))|| ((Attributes & (EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS)) == 0)) {
2286       if (Variable->InDeletedTransitionPtr != NULL) {
2287         //
2288         // Both ADDED and IN_DELETED_TRANSITION variable are present,
2289         // set IN_DELETED_TRANSITION one to DELETED state first.
2290         //
2291         ASSERT (CacheVariable->InDeletedTransitionPtr != NULL);
2292         State = CacheVariable->InDeletedTransitionPtr->State;
2293         State &= VAR_DELETED;
2294         Status = UpdateVariableStore (
2295                    &mVariableModuleGlobal->VariableGlobal,
2296                    Variable->Volatile,
2297                    FALSE,
2298                    Fvb,
2299                    (UINTN) &Variable->InDeletedTransitionPtr->State,
2300                    sizeof (UINT8),
2301                    &State
2302                    );
2303         if (!EFI_ERROR (Status)) {
2304           if (!Variable->Volatile) {
2305             CacheVariable->InDeletedTransitionPtr->State = State;
2306           }
2307         } else {
2308           goto Done;
2309         }
2310       }
2311 
2312       State = CacheVariable->CurrPtr->State;
2313       State &= VAR_DELETED;
2314 
2315       Status = UpdateVariableStore (
2316                  &mVariableModuleGlobal->VariableGlobal,
2317                  Variable->Volatile,
2318                  FALSE,
2319                  Fvb,
2320                  (UINTN) &Variable->CurrPtr->State,
2321                  sizeof (UINT8),
2322                  &State
2323                  );
2324       if (!EFI_ERROR (Status)) {
2325         UpdateVariableInfo (VariableName, VendorGuid, Variable->Volatile, FALSE, FALSE, TRUE, FALSE);
2326         if (!Variable->Volatile) {
2327           CacheVariable->CurrPtr->State = State;
2328           FlushHobVariableToFlash (VariableName, VendorGuid);
2329         }
2330       }
2331       goto Done;
2332     }
2333     //
2334     // If the variable is marked valid, and the same data has been passed in,
2335     // then return to the caller immediately.
2336     //
2337     if (DataSizeOfVariable (CacheVariable->CurrPtr) == DataSize &&
2338         (CompareMem (Data, GetVariableDataPtr (CacheVariable->CurrPtr), DataSize) == 0) &&
2339         ((Attributes & EFI_VARIABLE_APPEND_WRITE) == 0) &&
2340         (TimeStamp == NULL)) {
2341       //
2342       // Variable content unchanged and no need to update timestamp, just return.
2343       //
2344       UpdateVariableInfo (VariableName, VendorGuid, Variable->Volatile, FALSE, TRUE, FALSE, FALSE);
2345       Status = EFI_SUCCESS;
2346       goto Done;
2347     } else if ((CacheVariable->CurrPtr->State == VAR_ADDED) ||
2348                (CacheVariable->CurrPtr->State == (VAR_ADDED & VAR_IN_DELETED_TRANSITION))) {
2349 
2350       //
2351       // EFI_VARIABLE_APPEND_WRITE attribute only effects for existing variable.
2352       //
2353       if ((Attributes & EFI_VARIABLE_APPEND_WRITE) != 0) {
2354         //
2355         // NOTE: From 0 to DataOffset of NextVariable is reserved for Variable Header and Name.
2356         // From DataOffset of NextVariable is to save the existing variable data.
2357         //
2358         DataOffset = GetVariableDataOffset (CacheVariable->CurrPtr);
2359         BufferForMerge = (UINT8 *) ((UINTN) NextVariable + DataOffset);
2360         CopyMem (BufferForMerge, (UINT8 *) ((UINTN) CacheVariable->CurrPtr + DataOffset), DataSizeOfVariable (CacheVariable->CurrPtr));
2361 
2362         //
2363         // Set Max Auth/Non-Volatile/Volatile Variable Data Size as default MaxDataSize.
2364         //
2365         if ((Attributes & VARIABLE_ATTRIBUTE_AT_AW) != 0) {
2366           MaxDataSize = mVariableModuleGlobal->MaxAuthVariableSize - DataOffset;
2367         } else if ((Attributes & EFI_VARIABLE_NON_VOLATILE) != 0) {
2368           MaxDataSize = mVariableModuleGlobal->MaxVariableSize - DataOffset;
2369         } else {
2370           MaxDataSize = mVariableModuleGlobal->MaxVolatileVariableSize - DataOffset;
2371         }
2372 
2373         //
2374         // Append the new data to the end of existing data.
2375         // Max Harware error record variable data size is different from common/auth variable.
2376         //
2377         if ((Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == EFI_VARIABLE_HARDWARE_ERROR_RECORD) {
2378           MaxDataSize = PcdGet32 (PcdMaxHardwareErrorVariableSize) - DataOffset;
2379         }
2380 
2381         if (DataSizeOfVariable (CacheVariable->CurrPtr) + DataSize > MaxDataSize) {
2382           //
2383           // Existing data size + new data size exceed maximum variable size limitation.
2384           //
2385           Status = EFI_INVALID_PARAMETER;
2386           goto Done;
2387         }
2388         CopyMem ((UINT8*) ((UINTN) BufferForMerge + DataSizeOfVariable (CacheVariable->CurrPtr)), Data, DataSize);
2389         MergedBufSize = DataSizeOfVariable (CacheVariable->CurrPtr) + DataSize;
2390 
2391         //
2392         // BufferForMerge(from DataOffset of NextVariable) has included the merged existing and new data.
2393         //
2394         Data      = BufferForMerge;
2395         DataSize  = MergedBufSize;
2396         DataReady = TRUE;
2397       }
2398 
2399       //
2400       // Mark the old variable as in delete transition.
2401       //
2402       State = CacheVariable->CurrPtr->State;
2403       State &= VAR_IN_DELETED_TRANSITION;
2404 
2405       Status = UpdateVariableStore (
2406                  &mVariableModuleGlobal->VariableGlobal,
2407                  Variable->Volatile,
2408                  FALSE,
2409                  Fvb,
2410                  (UINTN) &Variable->CurrPtr->State,
2411                  sizeof (UINT8),
2412                  &State
2413                  );
2414       if (EFI_ERROR (Status)) {
2415         goto Done;
2416       }
2417       if (!Variable->Volatile) {
2418         CacheVariable->CurrPtr->State = State;
2419       }
2420     }
2421   } else {
2422     //
2423     // Not found existing variable. Create a new variable.
2424     //
2425 
2426     if ((DataSize == 0) && ((Attributes & EFI_VARIABLE_APPEND_WRITE) != 0)) {
2427       Status = EFI_SUCCESS;
2428       goto Done;
2429     }
2430 
2431     //
2432     // Make sure we are trying to create a new variable.
2433     // Setting a data variable with zero DataSize or no access attributes means to delete it.
2434     //
2435     if (DataSize == 0 || (Attributes & (EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS)) == 0) {
2436       Status = EFI_NOT_FOUND;
2437       goto Done;
2438     }
2439 
2440     //
2441     // Only variable have NV|RT attribute can be created in Runtime.
2442     //
2443     if (AtRuntime () &&
2444         (((Attributes & EFI_VARIABLE_RUNTIME_ACCESS) == 0) || ((Attributes & EFI_VARIABLE_NON_VOLATILE) == 0))) {
2445       Status = EFI_INVALID_PARAMETER;
2446       goto Done;
2447     }
2448   }
2449 
2450   //
2451   // Function part - create a new variable and copy the data.
2452   // Both update a variable and create a variable will come here.
2453   //
2454   NextVariable->StartId     = VARIABLE_DATA;
2455   //
2456   // NextVariable->State = VAR_ADDED;
2457   //
2458   NextVariable->Reserved        = 0;
2459   if (mVariableModuleGlobal->VariableGlobal.AuthFormat) {
2460     AuthVariable = (AUTHENTICATED_VARIABLE_HEADER *) NextVariable;
2461     AuthVariable->PubKeyIndex    = KeyIndex;
2462     AuthVariable->MonotonicCount = MonotonicCount;
2463     ZeroMem (&AuthVariable->TimeStamp, sizeof (EFI_TIME));
2464 
2465     if (((Attributes & EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS) != 0) &&
2466         (TimeStamp != NULL)) {
2467       if ((Attributes & EFI_VARIABLE_APPEND_WRITE) == 0) {
2468         CopyMem (&AuthVariable->TimeStamp, TimeStamp, sizeof (EFI_TIME));
2469       } else {
2470         //
2471         // In the case when the EFI_VARIABLE_APPEND_WRITE attribute is set, only
2472         // when the new TimeStamp value is later than the current timestamp associated
2473         // with the variable, we need associate the new timestamp with the updated value.
2474         //
2475         if (Variable->CurrPtr != NULL) {
2476           if (VariableCompareTimeStampInternal (&(((AUTHENTICATED_VARIABLE_HEADER *) CacheVariable->CurrPtr)->TimeStamp), TimeStamp)) {
2477             CopyMem (&AuthVariable->TimeStamp, TimeStamp, sizeof (EFI_TIME));
2478           } else {
2479             CopyMem (&AuthVariable->TimeStamp, &(((AUTHENTICATED_VARIABLE_HEADER *) CacheVariable->CurrPtr)->TimeStamp), sizeof (EFI_TIME));
2480           }
2481         }
2482       }
2483     }
2484   }
2485 
2486   //
2487   // The EFI_VARIABLE_APPEND_WRITE attribute will never be set in the returned
2488   // Attributes bitmask parameter of a GetVariable() call.
2489   //
2490   NextVariable->Attributes  = Attributes & (~EFI_VARIABLE_APPEND_WRITE);
2491 
2492   VarNameOffset                 = GetVariableHeaderSize ();
2493   VarNameSize                   = StrSize (VariableName);
2494   CopyMem (
2495     (UINT8 *) ((UINTN) NextVariable + VarNameOffset),
2496     VariableName,
2497     VarNameSize
2498     );
2499   VarDataOffset = VarNameOffset + VarNameSize + GET_PAD_SIZE (VarNameSize);
2500 
2501   //
2502   // If DataReady is TRUE, it means the variable data has been saved into
2503   // NextVariable during EFI_VARIABLE_APPEND_WRITE operation preparation.
2504   //
2505   if (!DataReady) {
2506     CopyMem (
2507       (UINT8 *) ((UINTN) NextVariable + VarDataOffset),
2508       Data,
2509       DataSize
2510       );
2511   }
2512 
2513   CopyMem (GetVendorGuidPtr (NextVariable), VendorGuid, sizeof (EFI_GUID));
2514   //
2515   // There will be pad bytes after Data, the NextVariable->NameSize and
2516   // NextVariable->DataSize should not include pad size so that variable
2517   // service can get actual size in GetVariable.
2518   //
2519   SetNameSizeOfVariable (NextVariable, VarNameSize);
2520   SetDataSizeOfVariable (NextVariable, DataSize);
2521 
2522   //
2523   // The actual size of the variable that stores in storage should
2524   // include pad size.
2525   //
2526   VarSize = VarDataOffset + DataSize + GET_PAD_SIZE (DataSize);
2527   if ((Attributes & EFI_VARIABLE_NON_VOLATILE) != 0) {
2528     //
2529     // Create a nonvolatile variable.
2530     //
2531     Volatile = FALSE;
2532 
2533     IsCommonVariable = FALSE;
2534     IsCommonUserVariable = FALSE;
2535     if ((Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == 0) {
2536       IsCommonVariable = TRUE;
2537       IsCommonUserVariable = IsUserVariable (NextVariable);
2538     }
2539     if ((((Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) != 0)
2540       && ((VarSize + mVariableModuleGlobal->HwErrVariableTotalSize) > PcdGet32 (PcdHwErrStorageSize)))
2541       || (IsCommonVariable && ((VarSize + mVariableModuleGlobal->CommonVariableTotalSize) > mVariableModuleGlobal->CommonVariableSpace))
2542       || (IsCommonVariable && AtRuntime () && ((VarSize + mVariableModuleGlobal->CommonVariableTotalSize) > mVariableModuleGlobal->CommonRuntimeVariableSpace))
2543       || (IsCommonUserVariable && ((VarSize + mVariableModuleGlobal->CommonUserVariableTotalSize) > mVariableModuleGlobal->CommonMaxUserVariableSpace))) {
2544       if (AtRuntime ()) {
2545         if (IsCommonUserVariable && ((VarSize + mVariableModuleGlobal->CommonUserVariableTotalSize) > mVariableModuleGlobal->CommonMaxUserVariableSpace)) {
2546           RecordVarErrorFlag (VAR_ERROR_FLAG_USER_ERROR, VariableName, VendorGuid, Attributes, VarSize);
2547         }
2548         if (IsCommonVariable && ((VarSize + mVariableModuleGlobal->CommonVariableTotalSize) > mVariableModuleGlobal->CommonRuntimeVariableSpace)) {
2549           RecordVarErrorFlag (VAR_ERROR_FLAG_SYSTEM_ERROR, VariableName, VendorGuid, Attributes, VarSize);
2550         }
2551         Status = EFI_OUT_OF_RESOURCES;
2552         goto Done;
2553       }
2554       //
2555       // Perform garbage collection & reclaim operation, and integrate the new variable at the same time.
2556       //
2557       Status = Reclaim (
2558                  mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase,
2559                  &mVariableModuleGlobal->NonVolatileLastVariableOffset,
2560                  FALSE,
2561                  Variable,
2562                  NextVariable,
2563                  HEADER_ALIGN (VarSize)
2564                  );
2565       if (!EFI_ERROR (Status)) {
2566         //
2567         // The new variable has been integrated successfully during reclaiming.
2568         //
2569         if (Variable->CurrPtr != NULL) {
2570           CacheVariable->CurrPtr = (VARIABLE_HEADER *)((UINTN) CacheVariable->StartPtr + ((UINTN) Variable->CurrPtr - (UINTN) Variable->StartPtr));
2571           CacheVariable->InDeletedTransitionPtr = NULL;
2572         }
2573         UpdateVariableInfo (VariableName, VendorGuid, FALSE, FALSE, TRUE, FALSE, FALSE);
2574         FlushHobVariableToFlash (VariableName, VendorGuid);
2575       } else {
2576         if (IsCommonUserVariable && ((VarSize + mVariableModuleGlobal->CommonUserVariableTotalSize) > mVariableModuleGlobal->CommonMaxUserVariableSpace)) {
2577           RecordVarErrorFlag (VAR_ERROR_FLAG_USER_ERROR, VariableName, VendorGuid, Attributes, VarSize);
2578         }
2579         if (IsCommonVariable && ((VarSize + mVariableModuleGlobal->CommonVariableTotalSize) > mVariableModuleGlobal->CommonVariableSpace)) {
2580           RecordVarErrorFlag (VAR_ERROR_FLAG_SYSTEM_ERROR, VariableName, VendorGuid, Attributes, VarSize);
2581         }
2582       }
2583       goto Done;
2584     }
2585 
2586     if (!mVariableModuleGlobal->VariableGlobal.EmuNvMode) {
2587       //
2588       // Four steps
2589       // 1. Write variable header
2590       // 2. Set variable state to header valid
2591       // 3. Write variable data
2592       // 4. Set variable state to valid
2593       //
2594       //
2595       // Step 1:
2596       //
2597       Status = UpdateVariableStore (
2598                  &mVariableModuleGlobal->VariableGlobal,
2599                  FALSE,
2600                  TRUE,
2601                  Fvb,
2602                  mVariableModuleGlobal->NonVolatileLastVariableOffset,
2603                  (UINT32) GetVariableHeaderSize (),
2604                  (UINT8 *) NextVariable
2605                  );
2606 
2607       if (EFI_ERROR (Status)) {
2608         goto Done;
2609       }
2610 
2611       //
2612       // Step 2:
2613       //
2614       NextVariable->State = VAR_HEADER_VALID_ONLY;
2615       Status = UpdateVariableStore (
2616                  &mVariableModuleGlobal->VariableGlobal,
2617                  FALSE,
2618                  TRUE,
2619                  Fvb,
2620                  mVariableModuleGlobal->NonVolatileLastVariableOffset + OFFSET_OF (VARIABLE_HEADER, State),
2621                  sizeof (UINT8),
2622                  &NextVariable->State
2623                  );
2624 
2625       if (EFI_ERROR (Status)) {
2626         goto Done;
2627       }
2628       //
2629       // Step 3:
2630       //
2631       Status = UpdateVariableStore (
2632                  &mVariableModuleGlobal->VariableGlobal,
2633                  FALSE,
2634                  TRUE,
2635                  Fvb,
2636                  mVariableModuleGlobal->NonVolatileLastVariableOffset + GetVariableHeaderSize (),
2637                  (UINT32) (VarSize - GetVariableHeaderSize ()),
2638                  (UINT8 *) NextVariable + GetVariableHeaderSize ()
2639                  );
2640 
2641       if (EFI_ERROR (Status)) {
2642         goto Done;
2643       }
2644       //
2645       // Step 4:
2646       //
2647       NextVariable->State = VAR_ADDED;
2648       Status = UpdateVariableStore (
2649                  &mVariableModuleGlobal->VariableGlobal,
2650                  FALSE,
2651                  TRUE,
2652                  Fvb,
2653                  mVariableModuleGlobal->NonVolatileLastVariableOffset + OFFSET_OF (VARIABLE_HEADER, State),
2654                  sizeof (UINT8),
2655                  &NextVariable->State
2656                  );
2657 
2658       if (EFI_ERROR (Status)) {
2659         goto Done;
2660       }
2661 
2662       //
2663       // Update the memory copy of Flash region.
2664       //
2665       CopyMem ((UINT8 *)mNvVariableCache + mVariableModuleGlobal->NonVolatileLastVariableOffset, (UINT8 *)NextVariable, VarSize);
2666     } else {
2667       //
2668       // Emulated non-volatile variable mode.
2669       //
2670       NextVariable->State = VAR_ADDED;
2671       Status = UpdateVariableStore (
2672                  &mVariableModuleGlobal->VariableGlobal,
2673                  FALSE,
2674                  TRUE,
2675                  Fvb,
2676                  mVariableModuleGlobal->NonVolatileLastVariableOffset,
2677                  (UINT32) VarSize,
2678                  (UINT8 *) NextVariable
2679                  );
2680 
2681       if (EFI_ERROR (Status)) {
2682         goto Done;
2683       }
2684     }
2685 
2686     mVariableModuleGlobal->NonVolatileLastVariableOffset += HEADER_ALIGN (VarSize);
2687 
2688     if ((Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) != 0) {
2689       mVariableModuleGlobal->HwErrVariableTotalSize += HEADER_ALIGN (VarSize);
2690     } else {
2691       mVariableModuleGlobal->CommonVariableTotalSize += HEADER_ALIGN (VarSize);
2692       if (IsCommonUserVariable) {
2693         mVariableModuleGlobal->CommonUserVariableTotalSize += HEADER_ALIGN (VarSize);
2694       }
2695     }
2696   } else {
2697     //
2698     // Create a volatile variable.
2699     //
2700     Volatile = TRUE;
2701 
2702     if ((UINT32) (VarSize + mVariableModuleGlobal->VolatileLastVariableOffset) >
2703         ((VARIABLE_STORE_HEADER *) ((UINTN) (mVariableModuleGlobal->VariableGlobal.VolatileVariableBase)))->Size) {
2704       //
2705       // Perform garbage collection & reclaim operation, and integrate the new variable at the same time.
2706       //
2707       Status = Reclaim (
2708                  mVariableModuleGlobal->VariableGlobal.VolatileVariableBase,
2709                  &mVariableModuleGlobal->VolatileLastVariableOffset,
2710                  TRUE,
2711                  Variable,
2712                  NextVariable,
2713                  HEADER_ALIGN (VarSize)
2714                  );
2715       if (!EFI_ERROR (Status)) {
2716         //
2717         // The new variable has been integrated successfully during reclaiming.
2718         //
2719         if (Variable->CurrPtr != NULL) {
2720           CacheVariable->CurrPtr = (VARIABLE_HEADER *)((UINTN) CacheVariable->StartPtr + ((UINTN) Variable->CurrPtr - (UINTN) Variable->StartPtr));
2721           CacheVariable->InDeletedTransitionPtr = NULL;
2722         }
2723         UpdateVariableInfo (VariableName, VendorGuid, TRUE, FALSE, TRUE, FALSE, FALSE);
2724       }
2725       goto Done;
2726     }
2727 
2728     NextVariable->State = VAR_ADDED;
2729     Status = UpdateVariableStore (
2730                &mVariableModuleGlobal->VariableGlobal,
2731                TRUE,
2732                TRUE,
2733                Fvb,
2734                mVariableModuleGlobal->VolatileLastVariableOffset,
2735                (UINT32) VarSize,
2736                (UINT8 *) NextVariable
2737                );
2738 
2739     if (EFI_ERROR (Status)) {
2740       goto Done;
2741     }
2742 
2743     mVariableModuleGlobal->VolatileLastVariableOffset += HEADER_ALIGN (VarSize);
2744   }
2745 
2746   //
2747   // Mark the old variable as deleted.
2748   //
2749   if (!EFI_ERROR (Status) && Variable->CurrPtr != NULL) {
2750     if (Variable->InDeletedTransitionPtr != NULL) {
2751       //
2752       // Both ADDED and IN_DELETED_TRANSITION old variable are present,
2753       // set IN_DELETED_TRANSITION one to DELETED state first.
2754       //
2755       ASSERT (CacheVariable->InDeletedTransitionPtr != NULL);
2756       State = CacheVariable->InDeletedTransitionPtr->State;
2757       State &= VAR_DELETED;
2758       Status = UpdateVariableStore (
2759                  &mVariableModuleGlobal->VariableGlobal,
2760                  Variable->Volatile,
2761                  FALSE,
2762                  Fvb,
2763                  (UINTN) &Variable->InDeletedTransitionPtr->State,
2764                  sizeof (UINT8),
2765                  &State
2766                  );
2767       if (!EFI_ERROR (Status)) {
2768         if (!Variable->Volatile) {
2769           CacheVariable->InDeletedTransitionPtr->State = State;
2770         }
2771       } else {
2772         goto Done;
2773       }
2774     }
2775 
2776     State = CacheVariable->CurrPtr->State;
2777     State &= VAR_DELETED;
2778 
2779     Status = UpdateVariableStore (
2780              &mVariableModuleGlobal->VariableGlobal,
2781              Variable->Volatile,
2782              FALSE,
2783              Fvb,
2784              (UINTN) &Variable->CurrPtr->State,
2785              sizeof (UINT8),
2786              &State
2787              );
2788     if (!EFI_ERROR (Status) && !Variable->Volatile) {
2789       CacheVariable->CurrPtr->State = State;
2790     }
2791   }
2792 
2793   if (!EFI_ERROR (Status)) {
2794     UpdateVariableInfo (VariableName, VendorGuid, Volatile, FALSE, TRUE, FALSE, FALSE);
2795     if (!Volatile) {
2796       FlushHobVariableToFlash (VariableName, VendorGuid);
2797     }
2798   }
2799 
2800 Done:
2801   return Status;
2802 }
2803 
2804 /**
2805 
2806   This code finds variable in storage blocks (Volatile or Non-Volatile).
2807 
2808   Caution: This function may receive untrusted input.
2809   This function may be invoked in SMM mode, and datasize is external input.
2810   This function will do basic validation, before parse the data.
2811 
2812   @param VariableName               Name of Variable to be found.
2813   @param VendorGuid                 Variable vendor GUID.
2814   @param Attributes                 Attribute value of the variable found.
2815   @param DataSize                   Size of Data found. If size is less than the
2816                                     data, this value contains the required size.
2817   @param Data                       The buffer to return the contents of the variable. May be NULL
2818                                     with a zero DataSize in order to determine the size buffer needed.
2819 
2820   @return EFI_INVALID_PARAMETER     Invalid parameter.
2821   @return EFI_SUCCESS               Find the specified variable.
2822   @return EFI_NOT_FOUND             Not found.
2823   @return EFI_BUFFER_TO_SMALL       DataSize is too small for the result.
2824 
2825 **/
2826 EFI_STATUS
2827 EFIAPI
VariableServiceGetVariable(IN CHAR16 * VariableName,IN EFI_GUID * VendorGuid,OUT UINT32 * Attributes OPTIONAL,IN OUT UINTN * DataSize,OUT VOID * Data OPTIONAL)2828 VariableServiceGetVariable (
2829   IN      CHAR16            *VariableName,
2830   IN      EFI_GUID          *VendorGuid,
2831   OUT     UINT32            *Attributes OPTIONAL,
2832   IN OUT  UINTN             *DataSize,
2833   OUT     VOID              *Data OPTIONAL
2834   )
2835 {
2836   EFI_STATUS              Status;
2837   VARIABLE_POINTER_TRACK  Variable;
2838   UINTN                   VarDataSize;
2839 
2840   if (VariableName == NULL || VendorGuid == NULL || DataSize == NULL) {
2841     return EFI_INVALID_PARAMETER;
2842   }
2843 
2844   if (VariableName[0] == 0) {
2845     return EFI_NOT_FOUND;
2846   }
2847 
2848   AcquireLockOnlyAtBootTime(&mVariableModuleGlobal->VariableGlobal.VariableServicesLock);
2849 
2850   Status = FindVariable (VariableName, VendorGuid, &Variable, &mVariableModuleGlobal->VariableGlobal, FALSE);
2851   if (Variable.CurrPtr == NULL || EFI_ERROR (Status)) {
2852     goto Done;
2853   }
2854 
2855   //
2856   // Get data size
2857   //
2858   VarDataSize = DataSizeOfVariable (Variable.CurrPtr);
2859   ASSERT (VarDataSize != 0);
2860 
2861   if (*DataSize >= VarDataSize) {
2862     if (Data == NULL) {
2863       Status = EFI_INVALID_PARAMETER;
2864       goto Done;
2865     }
2866 
2867     CopyMem (Data, GetVariableDataPtr (Variable.CurrPtr), VarDataSize);
2868     if (Attributes != NULL) {
2869       *Attributes = Variable.CurrPtr->Attributes;
2870     }
2871 
2872     *DataSize = VarDataSize;
2873     UpdateVariableInfo (VariableName, VendorGuid, Variable.Volatile, TRUE, FALSE, FALSE, FALSE);
2874 
2875     Status = EFI_SUCCESS;
2876     goto Done;
2877   } else {
2878     *DataSize = VarDataSize;
2879     Status = EFI_BUFFER_TOO_SMALL;
2880     goto Done;
2881   }
2882 
2883 Done:
2884   ReleaseLockOnlyAtBootTime (&mVariableModuleGlobal->VariableGlobal.VariableServicesLock);
2885   return Status;
2886 }
2887 
2888 /**
2889   This code Finds the Next available variable.
2890 
2891   Caution: This function may receive untrusted input.
2892   This function may be invoked in SMM mode. This function will do basic validation, before parse the data.
2893 
2894   @param[in]  VariableName  Pointer to variable name.
2895   @param[in]  VendorGuid    Variable Vendor Guid.
2896   @param[out] VariablePtr   Pointer to variable header address.
2897 
2898   @retval EFI_SUCCESS           The function completed successfully.
2899   @retval EFI_NOT_FOUND         The next variable was not found.
2900   @retval EFI_INVALID_PARAMETER If VariableName is not an empty string, while VendorGuid is NULL.
2901   @retval EFI_INVALID_PARAMETER The input values of VariableName and VendorGuid are not a name and
2902                                 GUID of an existing variable.
2903 
2904 **/
2905 EFI_STATUS
2906 EFIAPI
VariableServiceGetNextVariableInternal(IN CHAR16 * VariableName,IN EFI_GUID * VendorGuid,OUT VARIABLE_HEADER ** VariablePtr)2907 VariableServiceGetNextVariableInternal (
2908   IN  CHAR16                *VariableName,
2909   IN  EFI_GUID              *VendorGuid,
2910   OUT VARIABLE_HEADER       **VariablePtr
2911   )
2912 {
2913   VARIABLE_STORE_TYPE     Type;
2914   VARIABLE_POINTER_TRACK  Variable;
2915   VARIABLE_POINTER_TRACK  VariableInHob;
2916   VARIABLE_POINTER_TRACK  VariablePtrTrack;
2917   EFI_STATUS              Status;
2918   VARIABLE_STORE_HEADER   *VariableStoreHeader[VariableStoreTypeMax];
2919 
2920   Status = FindVariable (VariableName, VendorGuid, &Variable, &mVariableModuleGlobal->VariableGlobal, FALSE);
2921   if (Variable.CurrPtr == NULL || EFI_ERROR (Status)) {
2922     //
2923     // For VariableName is an empty string, FindVariable() will try to find and return
2924     // the first qualified variable, and if FindVariable() returns error (EFI_NOT_FOUND)
2925     // as no any variable is found, still go to return the error (EFI_NOT_FOUND).
2926     //
2927     if (VariableName[0] != 0) {
2928       //
2929       // For VariableName is not an empty string, and FindVariable() returns error as
2930       // VariableName and VendorGuid are not a name and GUID of an existing variable,
2931       // there is no way to get next variable, follow spec to return EFI_INVALID_PARAMETER.
2932       //
2933       Status = EFI_INVALID_PARAMETER;
2934     }
2935     goto Done;
2936   }
2937 
2938   if (VariableName[0] != 0) {
2939     //
2940     // If variable name is not NULL, get next variable.
2941     //
2942     Variable.CurrPtr = GetNextVariablePtr (Variable.CurrPtr);
2943   }
2944 
2945   //
2946   // 0: Volatile, 1: HOB, 2: Non-Volatile.
2947   // The index and attributes mapping must be kept in this order as FindVariable
2948   // makes use of this mapping to implement search algorithm.
2949   //
2950   VariableStoreHeader[VariableStoreTypeVolatile] = (VARIABLE_STORE_HEADER *) (UINTN) mVariableModuleGlobal->VariableGlobal.VolatileVariableBase;
2951   VariableStoreHeader[VariableStoreTypeHob]      = (VARIABLE_STORE_HEADER *) (UINTN) mVariableModuleGlobal->VariableGlobal.HobVariableBase;
2952   VariableStoreHeader[VariableStoreTypeNv]       = mNvVariableCache;
2953 
2954   while (TRUE) {
2955     //
2956     // Switch from Volatile to HOB, to Non-Volatile.
2957     //
2958     while (!IsValidVariableHeader (Variable.CurrPtr, Variable.EndPtr)) {
2959       //
2960       // Find current storage index
2961       //
2962       for (Type = (VARIABLE_STORE_TYPE) 0; Type < VariableStoreTypeMax; Type++) {
2963         if ((VariableStoreHeader[Type] != NULL) && (Variable.StartPtr == GetStartPointer (VariableStoreHeader[Type]))) {
2964           break;
2965         }
2966       }
2967       ASSERT (Type < VariableStoreTypeMax);
2968       //
2969       // Switch to next storage
2970       //
2971       for (Type++; Type < VariableStoreTypeMax; Type++) {
2972         if (VariableStoreHeader[Type] != NULL) {
2973           break;
2974         }
2975       }
2976       //
2977       // Capture the case that
2978       // 1. current storage is the last one, or
2979       // 2. no further storage
2980       //
2981       if (Type == VariableStoreTypeMax) {
2982         Status = EFI_NOT_FOUND;
2983         goto Done;
2984       }
2985       Variable.StartPtr = GetStartPointer (VariableStoreHeader[Type]);
2986       Variable.EndPtr   = GetEndPointer   (VariableStoreHeader[Type]);
2987       Variable.CurrPtr  = Variable.StartPtr;
2988     }
2989 
2990     //
2991     // Variable is found
2992     //
2993     if (Variable.CurrPtr->State == VAR_ADDED || Variable.CurrPtr->State == (VAR_IN_DELETED_TRANSITION & VAR_ADDED)) {
2994       if (!AtRuntime () || ((Variable.CurrPtr->Attributes & EFI_VARIABLE_RUNTIME_ACCESS) != 0)) {
2995         if (Variable.CurrPtr->State == (VAR_IN_DELETED_TRANSITION & VAR_ADDED)) {
2996           //
2997           // If it is a IN_DELETED_TRANSITION variable,
2998           // and there is also a same ADDED one at the same time,
2999           // don't return it.
3000           //
3001           VariablePtrTrack.StartPtr = Variable.StartPtr;
3002           VariablePtrTrack.EndPtr = Variable.EndPtr;
3003           Status = FindVariableEx (
3004                      GetVariableNamePtr (Variable.CurrPtr),
3005                      GetVendorGuidPtr (Variable.CurrPtr),
3006                      FALSE,
3007                      &VariablePtrTrack
3008                      );
3009           if (!EFI_ERROR (Status) && VariablePtrTrack.CurrPtr->State == VAR_ADDED) {
3010             Variable.CurrPtr = GetNextVariablePtr (Variable.CurrPtr);
3011             continue;
3012           }
3013         }
3014 
3015         //
3016         // Don't return NV variable when HOB overrides it
3017         //
3018         if ((VariableStoreHeader[VariableStoreTypeHob] != NULL) && (VariableStoreHeader[VariableStoreTypeNv] != NULL) &&
3019             (Variable.StartPtr == GetStartPointer (VariableStoreHeader[VariableStoreTypeNv]))
3020            ) {
3021           VariableInHob.StartPtr = GetStartPointer (VariableStoreHeader[VariableStoreTypeHob]);
3022           VariableInHob.EndPtr   = GetEndPointer   (VariableStoreHeader[VariableStoreTypeHob]);
3023           Status = FindVariableEx (
3024                      GetVariableNamePtr (Variable.CurrPtr),
3025                      GetVendorGuidPtr (Variable.CurrPtr),
3026                      FALSE,
3027                      &VariableInHob
3028                      );
3029           if (!EFI_ERROR (Status)) {
3030             Variable.CurrPtr = GetNextVariablePtr (Variable.CurrPtr);
3031             continue;
3032           }
3033         }
3034 
3035         *VariablePtr = Variable.CurrPtr;
3036         Status = EFI_SUCCESS;
3037         goto Done;
3038       }
3039     }
3040 
3041     Variable.CurrPtr = GetNextVariablePtr (Variable.CurrPtr);
3042   }
3043 
3044 Done:
3045   return Status;
3046 }
3047 
3048 /**
3049 
3050   This code Finds the Next available variable.
3051 
3052   Caution: This function may receive untrusted input.
3053   This function may be invoked in SMM mode. This function will do basic validation, before parse the data.
3054 
3055   @param VariableNameSize           The size of the VariableName buffer. The size must be large
3056                                     enough to fit input string supplied in VariableName buffer.
3057   @param VariableName               Pointer to variable name.
3058   @param VendorGuid                 Variable Vendor Guid.
3059 
3060   @retval EFI_SUCCESS               The function completed successfully.
3061   @retval EFI_NOT_FOUND             The next variable was not found.
3062   @retval EFI_BUFFER_TOO_SMALL      The VariableNameSize is too small for the result.
3063                                     VariableNameSize has been updated with the size needed to complete the request.
3064   @retval EFI_INVALID_PARAMETER     VariableNameSize is NULL.
3065   @retval EFI_INVALID_PARAMETER     VariableName is NULL.
3066   @retval EFI_INVALID_PARAMETER     VendorGuid is NULL.
3067   @retval EFI_INVALID_PARAMETER     The input values of VariableName and VendorGuid are not a name and
3068                                     GUID of an existing variable.
3069   @retval EFI_INVALID_PARAMETER     Null-terminator is not found in the first VariableNameSize bytes of
3070                                     the input VariableName buffer.
3071 
3072 **/
3073 EFI_STATUS
3074 EFIAPI
VariableServiceGetNextVariableName(IN OUT UINTN * VariableNameSize,IN OUT CHAR16 * VariableName,IN OUT EFI_GUID * VendorGuid)3075 VariableServiceGetNextVariableName (
3076   IN OUT  UINTN             *VariableNameSize,
3077   IN OUT  CHAR16            *VariableName,
3078   IN OUT  EFI_GUID          *VendorGuid
3079   )
3080 {
3081   EFI_STATUS              Status;
3082   UINTN                   MaxLen;
3083   UINTN                   VarNameSize;
3084   VARIABLE_HEADER         *VariablePtr;
3085 
3086   if (VariableNameSize == NULL || VariableName == NULL || VendorGuid == NULL) {
3087     return EFI_INVALID_PARAMETER;
3088   }
3089 
3090   //
3091   // Calculate the possible maximum length of name string, including the Null terminator.
3092   //
3093   MaxLen = *VariableNameSize / sizeof (CHAR16);
3094   if ((MaxLen == 0) || (StrnLenS (VariableName, MaxLen) == MaxLen)) {
3095     //
3096     // Null-terminator is not found in the first VariableNameSize bytes of the input VariableName buffer,
3097     // follow spec to return EFI_INVALID_PARAMETER.
3098     //
3099     return EFI_INVALID_PARAMETER;
3100   }
3101 
3102   AcquireLockOnlyAtBootTime(&mVariableModuleGlobal->VariableGlobal.VariableServicesLock);
3103 
3104   Status = VariableServiceGetNextVariableInternal (VariableName, VendorGuid, &VariablePtr);
3105   if (!EFI_ERROR (Status)) {
3106     VarNameSize = NameSizeOfVariable (VariablePtr);
3107     ASSERT (VarNameSize != 0);
3108     if (VarNameSize <= *VariableNameSize) {
3109       CopyMem (VariableName, GetVariableNamePtr (VariablePtr), VarNameSize);
3110       CopyMem (VendorGuid, GetVendorGuidPtr (VariablePtr), sizeof (EFI_GUID));
3111       Status = EFI_SUCCESS;
3112     } else {
3113       Status = EFI_BUFFER_TOO_SMALL;
3114     }
3115 
3116     *VariableNameSize = VarNameSize;
3117   }
3118 
3119   ReleaseLockOnlyAtBootTime (&mVariableModuleGlobal->VariableGlobal.VariableServicesLock);
3120   return Status;
3121 }
3122 
3123 /**
3124 
3125   This code sets variable in storage blocks (Volatile or Non-Volatile).
3126 
3127   Caution: This function may receive untrusted input.
3128   This function may be invoked in SMM mode, and datasize and data are external input.
3129   This function will do basic validation, before parse the data.
3130   This function will parse the authentication carefully to avoid security issues, like
3131   buffer overflow, integer overflow.
3132   This function will check attribute carefully to avoid authentication bypass.
3133 
3134   @param VariableName                     Name of Variable to be found.
3135   @param VendorGuid                       Variable vendor GUID.
3136   @param Attributes                       Attribute value of the variable found
3137   @param DataSize                         Size of Data found. If size is less than the
3138                                           data, this value contains the required size.
3139   @param Data                             Data pointer.
3140 
3141   @return EFI_INVALID_PARAMETER           Invalid parameter.
3142   @return EFI_SUCCESS                     Set successfully.
3143   @return EFI_OUT_OF_RESOURCES            Resource not enough to set variable.
3144   @return EFI_NOT_FOUND                   Not found.
3145   @return EFI_WRITE_PROTECTED             Variable is read-only.
3146 
3147 **/
3148 EFI_STATUS
3149 EFIAPI
VariableServiceSetVariable(IN CHAR16 * VariableName,IN EFI_GUID * VendorGuid,IN UINT32 Attributes,IN UINTN DataSize,IN VOID * Data)3150 VariableServiceSetVariable (
3151   IN CHAR16                  *VariableName,
3152   IN EFI_GUID                *VendorGuid,
3153   IN UINT32                  Attributes,
3154   IN UINTN                   DataSize,
3155   IN VOID                    *Data
3156   )
3157 {
3158   VARIABLE_POINTER_TRACK              Variable;
3159   EFI_STATUS                          Status;
3160   VARIABLE_HEADER                     *NextVariable;
3161   EFI_PHYSICAL_ADDRESS                Point;
3162   UINTN                               PayloadSize;
3163 
3164   //
3165   // Check input parameters.
3166   //
3167   if (VariableName == NULL || VariableName[0] == 0 || VendorGuid == NULL) {
3168     return EFI_INVALID_PARAMETER;
3169   }
3170 
3171   if (DataSize != 0 && Data == NULL) {
3172     return EFI_INVALID_PARAMETER;
3173   }
3174 
3175   //
3176   // Check for reserverd bit in variable attribute.
3177   // EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS is deprecated but we still allow
3178   // the delete operation of common authenticated variable at user physical presence.
3179   // So leave EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS attribute check to AuthVariableLib
3180   //
3181   if ((Attributes & (~(EFI_VARIABLE_ATTRIBUTES_MASK | EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS))) != 0) {
3182     return EFI_INVALID_PARAMETER;
3183   }
3184 
3185   //
3186   //  Make sure if runtime bit is set, boot service bit is set also.
3187   //
3188   if ((Attributes & (EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS)) == EFI_VARIABLE_RUNTIME_ACCESS) {
3189     if ((Attributes & EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS) != 0) {
3190       return EFI_UNSUPPORTED;
3191     } else {
3192       return EFI_INVALID_PARAMETER;
3193     }
3194   } else if ((Attributes & VARIABLE_ATTRIBUTE_AT_AW) != 0) {
3195     if (!mVariableModuleGlobal->VariableGlobal.AuthSupport) {
3196       //
3197       // Not support authenticated variable write.
3198       //
3199       return EFI_INVALID_PARAMETER;
3200     }
3201   } else if ((Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) != 0) {
3202     if (PcdGet32 (PcdHwErrStorageSize) == 0) {
3203       //
3204       // Not support harware error record variable variable.
3205       //
3206       return EFI_INVALID_PARAMETER;
3207     }
3208   }
3209 
3210   //
3211   // EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS and EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS attribute
3212   // cannot be set both.
3213   //
3214   if (((Attributes & EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS) == EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS)
3215      && ((Attributes & EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS) == EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS)) {
3216     return EFI_UNSUPPORTED;
3217   }
3218 
3219   if ((Attributes & EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS) == EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS) {
3220     //
3221     //  If DataSize == AUTHINFO_SIZE and then PayloadSize is 0.
3222     //  Maybe it's the delete operation of common authenticated variable at user physical presence.
3223     //
3224     if (DataSize != AUTHINFO_SIZE) {
3225       return EFI_UNSUPPORTED;
3226     }
3227     PayloadSize = DataSize - AUTHINFO_SIZE;
3228   } else if ((Attributes & EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS) == EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS) {
3229     //
3230     // Sanity check for EFI_VARIABLE_AUTHENTICATION_2 descriptor.
3231     //
3232     if (DataSize < OFFSET_OF_AUTHINFO2_CERT_DATA ||
3233       ((EFI_VARIABLE_AUTHENTICATION_2 *) Data)->AuthInfo.Hdr.dwLength > DataSize - (OFFSET_OF (EFI_VARIABLE_AUTHENTICATION_2, AuthInfo)) ||
3234       ((EFI_VARIABLE_AUTHENTICATION_2 *) Data)->AuthInfo.Hdr.dwLength < OFFSET_OF (WIN_CERTIFICATE_UEFI_GUID, CertData)) {
3235       return EFI_SECURITY_VIOLATION;
3236     }
3237     //
3238     // The VariableSpeculationBarrier() call here is to ensure the above sanity
3239     // check for the EFI_VARIABLE_AUTHENTICATION_2 descriptor has been completed
3240     // before the execution of subsequent codes.
3241     //
3242     VariableSpeculationBarrier ();
3243     PayloadSize = DataSize - AUTHINFO2_SIZE (Data);
3244   } else {
3245     PayloadSize = DataSize;
3246   }
3247 
3248   if ((UINTN)(~0) - PayloadSize < StrSize(VariableName)){
3249     //
3250     // Prevent whole variable size overflow
3251     //
3252     return EFI_INVALID_PARAMETER;
3253   }
3254 
3255   //
3256   //  The size of the VariableName, including the Unicode Null in bytes plus
3257   //  the DataSize is limited to maximum size of PcdGet32 (PcdMaxHardwareErrorVariableSize)
3258   //  bytes for HwErrRec#### variable.
3259   //
3260   if ((Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == EFI_VARIABLE_HARDWARE_ERROR_RECORD) {
3261     if (StrSize (VariableName) + PayloadSize > PcdGet32 (PcdMaxHardwareErrorVariableSize) - GetVariableHeaderSize ()) {
3262       return EFI_INVALID_PARAMETER;
3263     }
3264   } else {
3265     //
3266     //  The size of the VariableName, including the Unicode Null in bytes plus
3267     //  the DataSize is limited to maximum size of Max(Auth|Volatile)VariableSize bytes.
3268     //
3269     if ((Attributes & VARIABLE_ATTRIBUTE_AT_AW) != 0) {
3270       if (StrSize (VariableName) + PayloadSize > mVariableModuleGlobal->MaxAuthVariableSize - GetVariableHeaderSize ()) {
3271         DEBUG ((DEBUG_ERROR,
3272           "%a: Failed to set variable '%s' with Guid %g\n",
3273           __FUNCTION__, VariableName, VendorGuid));
3274         DEBUG ((DEBUG_ERROR,
3275           "NameSize(0x%x) + PayloadSize(0x%x) > "
3276           "MaxAuthVariableSize(0x%x) - HeaderSize(0x%x)\n",
3277           StrSize (VariableName), PayloadSize,
3278           mVariableModuleGlobal->MaxAuthVariableSize,
3279           GetVariableHeaderSize ()
3280           ));
3281         return EFI_INVALID_PARAMETER;
3282       }
3283     } else if ((Attributes & EFI_VARIABLE_NON_VOLATILE) != 0) {
3284       if (StrSize (VariableName) + PayloadSize > mVariableModuleGlobal->MaxVariableSize - GetVariableHeaderSize ()) {
3285         DEBUG ((DEBUG_ERROR,
3286           "%a: Failed to set variable '%s' with Guid %g\n",
3287           __FUNCTION__, VariableName, VendorGuid));
3288         DEBUG ((DEBUG_ERROR,
3289           "NameSize(0x%x) + PayloadSize(0x%x) > "
3290           "MaxVariableSize(0x%x) - HeaderSize(0x%x)\n",
3291           StrSize (VariableName), PayloadSize,
3292           mVariableModuleGlobal->MaxVariableSize,
3293           GetVariableHeaderSize ()
3294           ));
3295         return EFI_INVALID_PARAMETER;
3296       }
3297     } else {
3298       if (StrSize (VariableName) + PayloadSize > mVariableModuleGlobal->MaxVolatileVariableSize - GetVariableHeaderSize ()) {
3299         DEBUG ((DEBUG_ERROR,
3300           "%a: Failed to set variable '%s' with Guid %g\n",
3301           __FUNCTION__, VariableName, VendorGuid));
3302         DEBUG ((DEBUG_ERROR,
3303           "NameSize(0x%x) + PayloadSize(0x%x) > "
3304           "MaxVolatileVariableSize(0x%x) - HeaderSize(0x%x)\n",
3305           StrSize (VariableName), PayloadSize,
3306           mVariableModuleGlobal->MaxVolatileVariableSize,
3307           GetVariableHeaderSize ()
3308           ));
3309         return EFI_INVALID_PARAMETER;
3310       }
3311     }
3312   }
3313 
3314   //
3315   // Special Handling for MOR Lock variable.
3316   //
3317   Status = SetVariableCheckHandlerMor (VariableName, VendorGuid, Attributes, PayloadSize, (VOID *) ((UINTN) Data + DataSize - PayloadSize));
3318   if (Status == EFI_ALREADY_STARTED) {
3319     //
3320     // EFI_ALREADY_STARTED means the SetVariable() action is handled inside of SetVariableCheckHandlerMor().
3321     // Variable driver can just return SUCCESS.
3322     //
3323     return EFI_SUCCESS;
3324   }
3325   if (EFI_ERROR (Status)) {
3326     return Status;
3327   }
3328 
3329   Status = VarCheckLibSetVariableCheck (VariableName, VendorGuid, Attributes, PayloadSize, (VOID *) ((UINTN) Data + DataSize - PayloadSize), mRequestSource);
3330   if (EFI_ERROR (Status)) {
3331     return Status;
3332   }
3333 
3334   AcquireLockOnlyAtBootTime(&mVariableModuleGlobal->VariableGlobal.VariableServicesLock);
3335 
3336   //
3337   // Consider reentrant in MCA/INIT/NMI. It needs be reupdated.
3338   //
3339   if (1 < InterlockedIncrement (&mVariableModuleGlobal->VariableGlobal.ReentrantState)) {
3340     Point = mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase;
3341     //
3342     // Parse non-volatile variable data and get last variable offset.
3343     //
3344     NextVariable  = GetStartPointer ((VARIABLE_STORE_HEADER *) (UINTN) Point);
3345     while (IsValidVariableHeader (NextVariable, GetEndPointer ((VARIABLE_STORE_HEADER *) (UINTN) Point))) {
3346       NextVariable = GetNextVariablePtr (NextVariable);
3347     }
3348     mVariableModuleGlobal->NonVolatileLastVariableOffset = (UINTN) NextVariable - (UINTN) Point;
3349   }
3350 
3351   //
3352   // Check whether the input variable is already existed.
3353   //
3354   Status = FindVariable (VariableName, VendorGuid, &Variable, &mVariableModuleGlobal->VariableGlobal, TRUE);
3355   if (!EFI_ERROR (Status)) {
3356     if (((Variable.CurrPtr->Attributes & EFI_VARIABLE_RUNTIME_ACCESS) == 0) && AtRuntime ()) {
3357       Status = EFI_WRITE_PROTECTED;
3358       goto Done;
3359     }
3360     if (Attributes != 0 && (Attributes & (~EFI_VARIABLE_APPEND_WRITE)) != Variable.CurrPtr->Attributes) {
3361       //
3362       // If a preexisting variable is rewritten with different attributes, SetVariable() shall not
3363       // modify the variable and shall return EFI_INVALID_PARAMETER. Two exceptions to this rule:
3364       // 1. No access attributes specified
3365       // 2. The only attribute differing is EFI_VARIABLE_APPEND_WRITE
3366       //
3367       Status = EFI_INVALID_PARAMETER;
3368       DEBUG ((EFI_D_INFO, "[Variable]: Rewritten a preexisting variable(0x%08x) with different attributes(0x%08x) - %g:%s\n", Variable.CurrPtr->Attributes, Attributes, VendorGuid, VariableName));
3369       goto Done;
3370     }
3371   }
3372 
3373   if (!FeaturePcdGet (PcdUefiVariableDefaultLangDeprecate)) {
3374     //
3375     // Hook the operation of setting PlatformLangCodes/PlatformLang and LangCodes/Lang.
3376     //
3377     Status = AutoUpdateLangVariable (VariableName, Data, DataSize);
3378     if (EFI_ERROR (Status)) {
3379       //
3380       // The auto update operation failed, directly return to avoid inconsistency between PlatformLang and Lang.
3381       //
3382       goto Done;
3383     }
3384   }
3385 
3386   if (mVariableModuleGlobal->VariableGlobal.AuthSupport) {
3387     Status = AuthVariableLibProcessVariable (VariableName, VendorGuid, Data, DataSize, Attributes);
3388   } else {
3389     Status = UpdateVariable (VariableName, VendorGuid, Data, DataSize, Attributes, 0, 0, &Variable, NULL);
3390   }
3391 
3392 Done:
3393   InterlockedDecrement (&mVariableModuleGlobal->VariableGlobal.ReentrantState);
3394   ReleaseLockOnlyAtBootTime (&mVariableModuleGlobal->VariableGlobal.VariableServicesLock);
3395 
3396   if (!AtRuntime ()) {
3397     if (!EFI_ERROR (Status)) {
3398       SecureBootHook (
3399         VariableName,
3400         VendorGuid
3401         );
3402     }
3403   }
3404 
3405   return Status;
3406 }
3407 
3408 /**
3409 
3410   This code returns information about the EFI variables.
3411 
3412   Caution: This function may receive untrusted input.
3413   This function may be invoked in SMM mode. This function will do basic validation, before parse the data.
3414 
3415   @param Attributes                     Attributes bitmask to specify the type of variables
3416                                         on which to return information.
3417   @param MaximumVariableStorageSize     Pointer to the maximum size of the storage space available
3418                                         for the EFI variables associated with the attributes specified.
3419   @param RemainingVariableStorageSize   Pointer to the remaining size of the storage space available
3420                                         for EFI variables associated with the attributes specified.
3421   @param MaximumVariableSize            Pointer to the maximum size of an individual EFI variables
3422                                         associated with the attributes specified.
3423 
3424   @return EFI_SUCCESS                   Query successfully.
3425 
3426 **/
3427 EFI_STATUS
3428 EFIAPI
VariableServiceQueryVariableInfoInternal(IN UINT32 Attributes,OUT UINT64 * MaximumVariableStorageSize,OUT UINT64 * RemainingVariableStorageSize,OUT UINT64 * MaximumVariableSize)3429 VariableServiceQueryVariableInfoInternal (
3430   IN  UINT32                 Attributes,
3431   OUT UINT64                 *MaximumVariableStorageSize,
3432   OUT UINT64                 *RemainingVariableStorageSize,
3433   OUT UINT64                 *MaximumVariableSize
3434   )
3435 {
3436   VARIABLE_HEADER        *Variable;
3437   VARIABLE_HEADER        *NextVariable;
3438   UINT64                 VariableSize;
3439   VARIABLE_STORE_HEADER  *VariableStoreHeader;
3440   UINT64                 CommonVariableTotalSize;
3441   UINT64                 HwErrVariableTotalSize;
3442   EFI_STATUS             Status;
3443   VARIABLE_POINTER_TRACK VariablePtrTrack;
3444 
3445   CommonVariableTotalSize = 0;
3446   HwErrVariableTotalSize = 0;
3447 
3448   if((Attributes & EFI_VARIABLE_NON_VOLATILE) == 0) {
3449     //
3450     // Query is Volatile related.
3451     //
3452     VariableStoreHeader = (VARIABLE_STORE_HEADER *) ((UINTN) mVariableModuleGlobal->VariableGlobal.VolatileVariableBase);
3453   } else {
3454     //
3455     // Query is Non-Volatile related.
3456     //
3457     VariableStoreHeader = mNvVariableCache;
3458   }
3459 
3460   //
3461   // Now let's fill *MaximumVariableStorageSize *RemainingVariableStorageSize
3462   // with the storage size (excluding the storage header size).
3463   //
3464   *MaximumVariableStorageSize   = VariableStoreHeader->Size - sizeof (VARIABLE_STORE_HEADER);
3465 
3466   //
3467   // Harware error record variable needs larger size.
3468   //
3469   if ((Attributes & (EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_HARDWARE_ERROR_RECORD)) == (EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_HARDWARE_ERROR_RECORD)) {
3470     *MaximumVariableStorageSize = PcdGet32 (PcdHwErrStorageSize);
3471     *MaximumVariableSize = PcdGet32 (PcdMaxHardwareErrorVariableSize) - GetVariableHeaderSize ();
3472   } else {
3473     if ((Attributes & EFI_VARIABLE_NON_VOLATILE) != 0) {
3474       if (AtRuntime ()) {
3475         *MaximumVariableStorageSize = mVariableModuleGlobal->CommonRuntimeVariableSpace;
3476       } else {
3477         *MaximumVariableStorageSize = mVariableModuleGlobal->CommonVariableSpace;
3478       }
3479     }
3480 
3481     //
3482     // Let *MaximumVariableSize be Max(Auth|Volatile)VariableSize with the exception of the variable header size.
3483     //
3484     if ((Attributes & VARIABLE_ATTRIBUTE_AT_AW) != 0) {
3485       *MaximumVariableSize = mVariableModuleGlobal->MaxAuthVariableSize - GetVariableHeaderSize ();
3486     } else if ((Attributes & EFI_VARIABLE_NON_VOLATILE) != 0) {
3487       *MaximumVariableSize = mVariableModuleGlobal->MaxVariableSize - GetVariableHeaderSize ();
3488     } else {
3489       *MaximumVariableSize = mVariableModuleGlobal->MaxVolatileVariableSize - GetVariableHeaderSize ();
3490     }
3491   }
3492 
3493   //
3494   // Point to the starting address of the variables.
3495   //
3496   Variable = GetStartPointer (VariableStoreHeader);
3497 
3498   //
3499   // Now walk through the related variable store.
3500   //
3501   while (IsValidVariableHeader (Variable, GetEndPointer (VariableStoreHeader))) {
3502     NextVariable = GetNextVariablePtr (Variable);
3503     VariableSize = (UINT64) (UINTN) NextVariable - (UINT64) (UINTN) Variable;
3504 
3505     if (AtRuntime ()) {
3506       //
3507       // We don't take the state of the variables in mind
3508       // when calculating RemainingVariableStorageSize,
3509       // since the space occupied by variables not marked with
3510       // VAR_ADDED is not allowed to be reclaimed in Runtime.
3511       //
3512       if ((Variable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == EFI_VARIABLE_HARDWARE_ERROR_RECORD) {
3513         HwErrVariableTotalSize += VariableSize;
3514       } else {
3515         CommonVariableTotalSize += VariableSize;
3516       }
3517     } else {
3518       //
3519       // Only care about Variables with State VAR_ADDED, because
3520       // the space not marked as VAR_ADDED is reclaimable now.
3521       //
3522       if (Variable->State == VAR_ADDED) {
3523         if ((Variable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == EFI_VARIABLE_HARDWARE_ERROR_RECORD) {
3524           HwErrVariableTotalSize += VariableSize;
3525         } else {
3526           CommonVariableTotalSize += VariableSize;
3527         }
3528       } else if (Variable->State == (VAR_IN_DELETED_TRANSITION & VAR_ADDED)) {
3529         //
3530         // If it is a IN_DELETED_TRANSITION variable,
3531         // and there is not also a same ADDED one at the same time,
3532         // this IN_DELETED_TRANSITION variable is valid.
3533         //
3534         VariablePtrTrack.StartPtr = GetStartPointer (VariableStoreHeader);
3535         VariablePtrTrack.EndPtr   = GetEndPointer   (VariableStoreHeader);
3536         Status = FindVariableEx (
3537                    GetVariableNamePtr (Variable),
3538                    GetVendorGuidPtr (Variable),
3539                    FALSE,
3540                    &VariablePtrTrack
3541                    );
3542         if (!EFI_ERROR (Status) && VariablePtrTrack.CurrPtr->State != VAR_ADDED) {
3543           if ((Variable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == EFI_VARIABLE_HARDWARE_ERROR_RECORD) {
3544             HwErrVariableTotalSize += VariableSize;
3545           } else {
3546             CommonVariableTotalSize += VariableSize;
3547           }
3548         }
3549       }
3550     }
3551 
3552     //
3553     // Go to the next one.
3554     //
3555     Variable = NextVariable;
3556   }
3557 
3558   if ((Attributes  & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == EFI_VARIABLE_HARDWARE_ERROR_RECORD){
3559     *RemainingVariableStorageSize = *MaximumVariableStorageSize - HwErrVariableTotalSize;
3560   } else {
3561     if (*MaximumVariableStorageSize < CommonVariableTotalSize) {
3562       *RemainingVariableStorageSize = 0;
3563     } else {
3564       *RemainingVariableStorageSize = *MaximumVariableStorageSize - CommonVariableTotalSize;
3565     }
3566   }
3567 
3568   if (*RemainingVariableStorageSize < GetVariableHeaderSize ()) {
3569     *MaximumVariableSize = 0;
3570   } else if ((*RemainingVariableStorageSize - GetVariableHeaderSize ()) < *MaximumVariableSize) {
3571     *MaximumVariableSize = *RemainingVariableStorageSize - GetVariableHeaderSize ();
3572   }
3573 
3574   return EFI_SUCCESS;
3575 }
3576 
3577 /**
3578 
3579   This code returns information about the EFI variables.
3580 
3581   Caution: This function may receive untrusted input.
3582   This function may be invoked in SMM mode. This function will do basic validation, before parse the data.
3583 
3584   @param Attributes                     Attributes bitmask to specify the type of variables
3585                                         on which to return information.
3586   @param MaximumVariableStorageSize     Pointer to the maximum size of the storage space available
3587                                         for the EFI variables associated with the attributes specified.
3588   @param RemainingVariableStorageSize   Pointer to the remaining size of the storage space available
3589                                         for EFI variables associated with the attributes specified.
3590   @param MaximumVariableSize            Pointer to the maximum size of an individual EFI variables
3591                                         associated with the attributes specified.
3592 
3593   @return EFI_INVALID_PARAMETER         An invalid combination of attribute bits was supplied.
3594   @return EFI_SUCCESS                   Query successfully.
3595   @return EFI_UNSUPPORTED               The attribute is not supported on this platform.
3596 
3597 **/
3598 EFI_STATUS
3599 EFIAPI
VariableServiceQueryVariableInfo(IN UINT32 Attributes,OUT UINT64 * MaximumVariableStorageSize,OUT UINT64 * RemainingVariableStorageSize,OUT UINT64 * MaximumVariableSize)3600 VariableServiceQueryVariableInfo (
3601   IN  UINT32                 Attributes,
3602   OUT UINT64                 *MaximumVariableStorageSize,
3603   OUT UINT64                 *RemainingVariableStorageSize,
3604   OUT UINT64                 *MaximumVariableSize
3605   )
3606 {
3607   EFI_STATUS             Status;
3608 
3609   if(MaximumVariableStorageSize == NULL || RemainingVariableStorageSize == NULL || MaximumVariableSize == NULL || Attributes == 0) {
3610     return EFI_INVALID_PARAMETER;
3611   }
3612 
3613   if ((Attributes & EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS) != 0) {
3614     //
3615     //  Deprecated attribute, make this check as highest priority.
3616     //
3617     return EFI_UNSUPPORTED;
3618   }
3619 
3620   if ((Attributes & EFI_VARIABLE_ATTRIBUTES_MASK) == 0) {
3621     //
3622     // Make sure the Attributes combination is supported by the platform.
3623     //
3624     return EFI_UNSUPPORTED;
3625   } else if ((Attributes & (EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS)) == EFI_VARIABLE_RUNTIME_ACCESS) {
3626     //
3627     // Make sure if runtime bit is set, boot service bit is set also.
3628     //
3629     return EFI_INVALID_PARAMETER;
3630   } else if (AtRuntime () && ((Attributes & EFI_VARIABLE_RUNTIME_ACCESS) == 0)) {
3631     //
3632     // Make sure RT Attribute is set if we are in Runtime phase.
3633     //
3634     return EFI_INVALID_PARAMETER;
3635   } else if ((Attributes & (EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_HARDWARE_ERROR_RECORD)) == EFI_VARIABLE_HARDWARE_ERROR_RECORD) {
3636     //
3637     // Make sure Hw Attribute is set with NV.
3638     //
3639     return EFI_INVALID_PARAMETER;
3640   } else if ((Attributes & VARIABLE_ATTRIBUTE_AT_AW) != 0) {
3641     if (!mVariableModuleGlobal->VariableGlobal.AuthSupport) {
3642       //
3643       // Not support authenticated variable write.
3644       //
3645       return EFI_UNSUPPORTED;
3646     }
3647   } else if ((Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) != 0) {
3648     if (PcdGet32 (PcdHwErrStorageSize) == 0) {
3649       //
3650       // Not support harware error record variable variable.
3651       //
3652       return EFI_UNSUPPORTED;
3653     }
3654   }
3655 
3656   AcquireLockOnlyAtBootTime(&mVariableModuleGlobal->VariableGlobal.VariableServicesLock);
3657 
3658   Status = VariableServiceQueryVariableInfoInternal (
3659              Attributes,
3660              MaximumVariableStorageSize,
3661              RemainingVariableStorageSize,
3662              MaximumVariableSize
3663              );
3664 
3665   ReleaseLockOnlyAtBootTime (&mVariableModuleGlobal->VariableGlobal.VariableServicesLock);
3666   return Status;
3667 }
3668 
3669 /**
3670   This function reclaims variable storage if free size is below the threshold.
3671 
3672   Caution: This function may be invoked at SMM mode.
3673   Care must be taken to make sure not security issue.
3674 
3675 **/
3676 VOID
ReclaimForOS(VOID)3677 ReclaimForOS(
3678   VOID
3679   )
3680 {
3681   EFI_STATUS                     Status;
3682   UINTN                          RemainingCommonRuntimeVariableSpace;
3683   UINTN                          RemainingHwErrVariableSpace;
3684   STATIC BOOLEAN                 Reclaimed;
3685 
3686   //
3687   // This function will be called only once at EndOfDxe or ReadyToBoot event.
3688   //
3689   if (Reclaimed) {
3690     return;
3691   }
3692   Reclaimed = TRUE;
3693 
3694   Status  = EFI_SUCCESS;
3695 
3696   if (mVariableModuleGlobal->CommonRuntimeVariableSpace < mVariableModuleGlobal->CommonVariableTotalSize) {
3697     RemainingCommonRuntimeVariableSpace = 0;
3698   } else {
3699     RemainingCommonRuntimeVariableSpace = mVariableModuleGlobal->CommonRuntimeVariableSpace - mVariableModuleGlobal->CommonVariableTotalSize;
3700   }
3701 
3702   RemainingHwErrVariableSpace = PcdGet32 (PcdHwErrStorageSize) - mVariableModuleGlobal->HwErrVariableTotalSize;
3703 
3704   //
3705   // Check if the free area is below a threshold.
3706   //
3707   if (((RemainingCommonRuntimeVariableSpace < mVariableModuleGlobal->MaxVariableSize) ||
3708        (RemainingCommonRuntimeVariableSpace < mVariableModuleGlobal->MaxAuthVariableSize)) ||
3709       ((PcdGet32 (PcdHwErrStorageSize) != 0) &&
3710        (RemainingHwErrVariableSpace < PcdGet32 (PcdMaxHardwareErrorVariableSize)))){
3711     Status = Reclaim (
3712             mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase,
3713             &mVariableModuleGlobal->NonVolatileLastVariableOffset,
3714             FALSE,
3715             NULL,
3716             NULL,
3717             0
3718             );
3719     ASSERT_EFI_ERROR (Status);
3720   }
3721 }
3722 
3723 /**
3724   Get non-volatile maximum variable size.
3725 
3726   @return Non-volatile maximum variable size.
3727 
3728 **/
3729 UINTN
GetNonVolatileMaxVariableSize(VOID)3730 GetNonVolatileMaxVariableSize (
3731   VOID
3732   )
3733 {
3734   if (PcdGet32 (PcdHwErrStorageSize) != 0) {
3735     return MAX (MAX (PcdGet32 (PcdMaxVariableSize), PcdGet32 (PcdMaxAuthVariableSize)),
3736                 PcdGet32 (PcdMaxHardwareErrorVariableSize));
3737   } else {
3738     return MAX (PcdGet32 (PcdMaxVariableSize), PcdGet32 (PcdMaxAuthVariableSize));
3739   }
3740 }
3741 
3742 /**
3743   Get maximum variable size, covering both non-volatile and volatile variables.
3744 
3745   @return Maximum variable size.
3746 
3747 **/
3748 UINTN
GetMaxVariableSize(VOID)3749 GetMaxVariableSize (
3750   VOID
3751   )
3752 {
3753   UINTN MaxVariableSize;
3754 
3755   MaxVariableSize = GetNonVolatileMaxVariableSize();
3756   //
3757   // The condition below fails implicitly if PcdMaxVolatileVariableSize equals
3758   // the default zero value.
3759   //
3760   if (MaxVariableSize < PcdGet32 (PcdMaxVolatileVariableSize)) {
3761     MaxVariableSize = PcdGet32 (PcdMaxVolatileVariableSize);
3762   }
3763   return MaxVariableSize;
3764 }
3765 
3766 /**
3767   Init real non-volatile variable store.
3768 
3769   @param[out] VariableStoreBase Output pointer to real non-volatile variable store base.
3770 
3771   @retval EFI_SUCCESS           Function successfully executed.
3772   @retval EFI_OUT_OF_RESOURCES  Fail to allocate enough memory resource.
3773   @retval EFI_VOLUME_CORRUPTED  Variable Store or Firmware Volume for Variable Store is corrupted.
3774 
3775 **/
3776 EFI_STATUS
InitRealNonVolatileVariableStore(OUT EFI_PHYSICAL_ADDRESS * VariableStoreBase)3777 InitRealNonVolatileVariableStore (
3778   OUT EFI_PHYSICAL_ADDRESS              *VariableStoreBase
3779   )
3780 {
3781   EFI_FIRMWARE_VOLUME_HEADER            *FvHeader;
3782   VARIABLE_STORE_HEADER                 *VariableStore;
3783   UINT32                                VariableStoreLength;
3784   EFI_HOB_GUID_TYPE                     *GuidHob;
3785   EFI_PHYSICAL_ADDRESS                  NvStorageBase;
3786   UINT8                                 *NvStorageData;
3787   UINT32                                NvStorageSize;
3788   FAULT_TOLERANT_WRITE_LAST_WRITE_DATA  *FtwLastWriteData;
3789   UINT32                                BackUpOffset;
3790   UINT32                                BackUpSize;
3791   UINT32                                HwErrStorageSize;
3792   UINT32                                MaxUserNvVariableSpaceSize;
3793   UINT32                                BoottimeReservedNvVariableSpaceSize;
3794   EFI_STATUS                            Status;
3795   VOID                                  *FtwProtocol;
3796 
3797   mVariableModuleGlobal->FvbInstance = NULL;
3798 
3799   //
3800   // Allocate runtime memory used for a memory copy of the FLASH region.
3801   // Keep the memory and the FLASH in sync as updates occur.
3802   //
3803   NvStorageSize = PcdGet32 (PcdFlashNvStorageVariableSize);
3804   NvStorageData = AllocateRuntimeZeroPool (NvStorageSize);
3805   if (NvStorageData == NULL) {
3806     return EFI_OUT_OF_RESOURCES;
3807   }
3808 
3809   NvStorageBase = NV_STORAGE_VARIABLE_BASE;
3810   ASSERT (NvStorageBase != 0);
3811 
3812   //
3813   // Copy NV storage data to the memory buffer.
3814   //
3815   CopyMem (NvStorageData, (UINT8 *) (UINTN) NvStorageBase, NvStorageSize);
3816 
3817   Status = GetFtwProtocol ((VOID **)&FtwProtocol);
3818   //
3819   // If FTW protocol has been installed, no need to check FTW last write data hob.
3820   //
3821   if (EFI_ERROR (Status)) {
3822     //
3823     // Check the FTW last write data hob.
3824     //
3825     GuidHob = GetFirstGuidHob (&gEdkiiFaultTolerantWriteGuid);
3826     if (GuidHob != NULL) {
3827       FtwLastWriteData = (FAULT_TOLERANT_WRITE_LAST_WRITE_DATA *) GET_GUID_HOB_DATA (GuidHob);
3828       if (FtwLastWriteData->TargetAddress == NvStorageBase) {
3829         DEBUG ((EFI_D_INFO, "Variable: NV storage is backed up in spare block: 0x%x\n", (UINTN) FtwLastWriteData->SpareAddress));
3830         //
3831         // Copy the backed up NV storage data to the memory buffer from spare block.
3832         //
3833         CopyMem (NvStorageData, (UINT8 *) (UINTN) (FtwLastWriteData->SpareAddress), NvStorageSize);
3834       } else if ((FtwLastWriteData->TargetAddress > NvStorageBase) &&
3835                  (FtwLastWriteData->TargetAddress < (NvStorageBase + NvStorageSize))) {
3836         //
3837         // Flash NV storage from the Offset is backed up in spare block.
3838         //
3839         BackUpOffset = (UINT32) (FtwLastWriteData->TargetAddress - NvStorageBase);
3840         BackUpSize = NvStorageSize - BackUpOffset;
3841         DEBUG ((EFI_D_INFO, "Variable: High partial NV storage from offset: %x is backed up in spare block: 0x%x\n", BackUpOffset, (UINTN) FtwLastWriteData->SpareAddress));
3842         //
3843         // Copy the partial backed up NV storage data to the memory buffer from spare block.
3844         //
3845         CopyMem (NvStorageData + BackUpOffset, (UINT8 *) (UINTN) FtwLastWriteData->SpareAddress, BackUpSize);
3846       }
3847     }
3848   }
3849 
3850   FvHeader = (EFI_FIRMWARE_VOLUME_HEADER *) NvStorageData;
3851 
3852   //
3853   // Check if the Firmware Volume is not corrupted
3854   //
3855   if ((FvHeader->Signature != EFI_FVH_SIGNATURE) || (!CompareGuid (&gEfiSystemNvDataFvGuid, &FvHeader->FileSystemGuid))) {
3856     FreePool (NvStorageData);
3857     DEBUG ((EFI_D_ERROR, "Firmware Volume for Variable Store is corrupted\n"));
3858     return EFI_VOLUME_CORRUPTED;
3859   }
3860 
3861   VariableStore = (VARIABLE_STORE_HEADER *) ((UINTN) FvHeader + FvHeader->HeaderLength);
3862   VariableStoreLength = NvStorageSize - FvHeader->HeaderLength;
3863   ASSERT (sizeof (VARIABLE_STORE_HEADER) <= VariableStoreLength);
3864   ASSERT (VariableStore->Size == VariableStoreLength);
3865 
3866   //
3867   // Check if the Variable Store header is not corrupted
3868   //
3869   if (GetVariableStoreStatus (VariableStore) != EfiValid) {
3870     FreePool (NvStorageData);
3871     DEBUG((EFI_D_ERROR, "Variable Store header is corrupted\n"));
3872     return EFI_VOLUME_CORRUPTED;
3873   }
3874 
3875   mNvFvHeaderCache = FvHeader;
3876 
3877   *VariableStoreBase = (EFI_PHYSICAL_ADDRESS) (UINTN) VariableStore;
3878 
3879   HwErrStorageSize = PcdGet32 (PcdHwErrStorageSize);
3880   MaxUserNvVariableSpaceSize = PcdGet32 (PcdMaxUserNvVariableSpaceSize);
3881   BoottimeReservedNvVariableSpaceSize = PcdGet32 (PcdBoottimeReservedNvVariableSpaceSize);
3882 
3883   //
3884   // Note that in EdkII variable driver implementation, Hardware Error Record type variable
3885   // is stored with common variable in the same NV region. So the platform integrator should
3886   // ensure that the value of PcdHwErrStorageSize is less than the value of
3887   // (VariableStoreLength - sizeof (VARIABLE_STORE_HEADER)).
3888   //
3889   ASSERT (HwErrStorageSize < (VariableStoreLength - sizeof (VARIABLE_STORE_HEADER)));
3890   //
3891   // Ensure that the value of PcdMaxUserNvVariableSpaceSize is less than the value of
3892   // (VariableStoreLength - sizeof (VARIABLE_STORE_HEADER)) - PcdGet32 (PcdHwErrStorageSize).
3893   //
3894   ASSERT (MaxUserNvVariableSpaceSize < (VariableStoreLength - sizeof (VARIABLE_STORE_HEADER) - HwErrStorageSize));
3895   //
3896   // Ensure that the value of PcdBoottimeReservedNvVariableSpaceSize is less than the value of
3897   // (VariableStoreLength - sizeof (VARIABLE_STORE_HEADER)) - PcdGet32 (PcdHwErrStorageSize).
3898   //
3899   ASSERT (BoottimeReservedNvVariableSpaceSize < (VariableStoreLength - sizeof (VARIABLE_STORE_HEADER) - HwErrStorageSize));
3900 
3901   mVariableModuleGlobal->CommonVariableSpace = ((UINTN) VariableStoreLength - sizeof (VARIABLE_STORE_HEADER) - HwErrStorageSize);
3902   mVariableModuleGlobal->CommonMaxUserVariableSpace = ((MaxUserNvVariableSpaceSize != 0) ? MaxUserNvVariableSpaceSize : mVariableModuleGlobal->CommonVariableSpace);
3903   mVariableModuleGlobal->CommonRuntimeVariableSpace = mVariableModuleGlobal->CommonVariableSpace - BoottimeReservedNvVariableSpaceSize;
3904 
3905   DEBUG ((EFI_D_INFO, "Variable driver common space: 0x%x 0x%x 0x%x\n", mVariableModuleGlobal->CommonVariableSpace, mVariableModuleGlobal->CommonMaxUserVariableSpace, mVariableModuleGlobal->CommonRuntimeVariableSpace));
3906 
3907   //
3908   // The max NV variable size should be < (VariableStoreLength - sizeof (VARIABLE_STORE_HEADER)).
3909   //
3910   ASSERT (GetNonVolatileMaxVariableSize () < (VariableStoreLength - sizeof (VARIABLE_STORE_HEADER)));
3911 
3912   return EFI_SUCCESS;
3913 }
3914 
3915 /**
3916   Init emulated non-volatile variable store.
3917 
3918   @param[out] VariableStoreBase Output pointer to emulated non-volatile variable store base.
3919 
3920   @retval EFI_SUCCESS           Function successfully executed.
3921   @retval EFI_OUT_OF_RESOURCES  Fail to allocate enough memory resource.
3922 
3923 **/
3924 EFI_STATUS
InitEmuNonVolatileVariableStore(EFI_PHYSICAL_ADDRESS * VariableStoreBase)3925 InitEmuNonVolatileVariableStore (
3926   EFI_PHYSICAL_ADDRESS  *VariableStoreBase
3927   )
3928 {
3929   VARIABLE_STORE_HEADER *VariableStore;
3930   UINT32                VariableStoreLength;
3931   BOOLEAN               FullyInitializeStore;
3932   UINT32                HwErrStorageSize;
3933 
3934   FullyInitializeStore = TRUE;
3935 
3936   VariableStoreLength = PcdGet32 (PcdVariableStoreSize);
3937   ASSERT (sizeof (VARIABLE_STORE_HEADER) <= VariableStoreLength);
3938 
3939   //
3940   // Allocate memory for variable store.
3941   //
3942   if (PcdGet64 (PcdEmuVariableNvStoreReserved) == 0) {
3943     VariableStore = (VARIABLE_STORE_HEADER *) AllocateRuntimePool (VariableStoreLength);
3944     if (VariableStore == NULL) {
3945       return EFI_OUT_OF_RESOURCES;
3946     }
3947   } else {
3948     //
3949     // A memory location has been reserved for the NV variable store.  Certain
3950     // platforms may be able to preserve a memory range across system resets,
3951     // thereby providing better NV variable emulation.
3952     //
3953     VariableStore =
3954       (VARIABLE_STORE_HEADER *)(VOID*)(UINTN)
3955         PcdGet64 (PcdEmuVariableNvStoreReserved);
3956     if ((VariableStore->Size == VariableStoreLength) &&
3957         (CompareGuid (&VariableStore->Signature, &gEfiAuthenticatedVariableGuid) ||
3958          CompareGuid (&VariableStore->Signature, &gEfiVariableGuid)) &&
3959         (VariableStore->Format == VARIABLE_STORE_FORMATTED) &&
3960         (VariableStore->State == VARIABLE_STORE_HEALTHY)) {
3961       DEBUG((
3962         DEBUG_INFO,
3963         "Variable Store reserved at %p appears to be valid\n",
3964         VariableStore
3965         ));
3966       FullyInitializeStore = FALSE;
3967     }
3968   }
3969 
3970   if (FullyInitializeStore) {
3971     SetMem (VariableStore, VariableStoreLength, 0xff);
3972     //
3973     // Use gEfiAuthenticatedVariableGuid for potential auth variable support.
3974     //
3975     CopyGuid (&VariableStore->Signature, &gEfiAuthenticatedVariableGuid);
3976     VariableStore->Size       = VariableStoreLength;
3977     VariableStore->Format     = VARIABLE_STORE_FORMATTED;
3978     VariableStore->State      = VARIABLE_STORE_HEALTHY;
3979     VariableStore->Reserved   = 0;
3980     VariableStore->Reserved1  = 0;
3981   }
3982 
3983   *VariableStoreBase = (EFI_PHYSICAL_ADDRESS) (UINTN) VariableStore;
3984 
3985   HwErrStorageSize = PcdGet32 (PcdHwErrStorageSize);
3986 
3987   //
3988   // Note that in EdkII variable driver implementation, Hardware Error Record type variable
3989   // is stored with common variable in the same NV region. So the platform integrator should
3990   // ensure that the value of PcdHwErrStorageSize is less than the value of
3991   // (VariableStoreLength - sizeof (VARIABLE_STORE_HEADER)).
3992   //
3993   ASSERT (HwErrStorageSize < (VariableStoreLength - sizeof (VARIABLE_STORE_HEADER)));
3994 
3995   mVariableModuleGlobal->CommonVariableSpace = ((UINTN) VariableStoreLength - sizeof (VARIABLE_STORE_HEADER) - HwErrStorageSize);
3996   mVariableModuleGlobal->CommonMaxUserVariableSpace = mVariableModuleGlobal->CommonVariableSpace;
3997   mVariableModuleGlobal->CommonRuntimeVariableSpace = mVariableModuleGlobal->CommonVariableSpace;
3998 
3999   return EFI_SUCCESS;
4000 }
4001 
4002 /**
4003   Init non-volatile variable store.
4004 
4005   @retval EFI_SUCCESS           Function successfully executed.
4006   @retval EFI_OUT_OF_RESOURCES  Fail to allocate enough memory resource.
4007   @retval EFI_VOLUME_CORRUPTED  Variable Store or Firmware Volume for Variable Store is corrupted.
4008 
4009 **/
4010 EFI_STATUS
InitNonVolatileVariableStore(VOID)4011 InitNonVolatileVariableStore (
4012   VOID
4013   )
4014 {
4015   VARIABLE_HEADER                       *Variable;
4016   VARIABLE_HEADER                       *NextVariable;
4017   EFI_PHYSICAL_ADDRESS                  VariableStoreBase;
4018   UINTN                                 VariableSize;
4019   EFI_STATUS                            Status;
4020 
4021   if (PcdGetBool (PcdEmuVariableNvModeEnable)) {
4022     Status = InitEmuNonVolatileVariableStore (&VariableStoreBase);
4023     if (EFI_ERROR (Status)) {
4024       return Status;
4025     }
4026     mVariableModuleGlobal->VariableGlobal.EmuNvMode = TRUE;
4027     DEBUG ((DEBUG_INFO, "Variable driver will work at emulated non-volatile variable mode!\n"));
4028   } else {
4029     Status = InitRealNonVolatileVariableStore (&VariableStoreBase);
4030     if (EFI_ERROR (Status)) {
4031       return Status;
4032     }
4033     mVariableModuleGlobal->VariableGlobal.EmuNvMode = FALSE;
4034   }
4035 
4036   mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase = VariableStoreBase;
4037   mNvVariableCache = (VARIABLE_STORE_HEADER *) (UINTN) VariableStoreBase;
4038   mVariableModuleGlobal->VariableGlobal.AuthFormat = (BOOLEAN)(CompareGuid (&mNvVariableCache->Signature, &gEfiAuthenticatedVariableGuid));
4039 
4040   mVariableModuleGlobal->MaxVariableSize = PcdGet32 (PcdMaxVariableSize);
4041   mVariableModuleGlobal->MaxAuthVariableSize = ((PcdGet32 (PcdMaxAuthVariableSize) != 0) ? PcdGet32 (PcdMaxAuthVariableSize) : mVariableModuleGlobal->MaxVariableSize);
4042 
4043   //
4044   // Parse non-volatile variable data and get last variable offset.
4045   //
4046   Variable  = GetStartPointer (mNvVariableCache);
4047   while (IsValidVariableHeader (Variable, GetEndPointer (mNvVariableCache))) {
4048     NextVariable = GetNextVariablePtr (Variable);
4049     VariableSize = (UINTN) NextVariable - (UINTN) Variable;
4050     if ((Variable->Attributes & (EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_HARDWARE_ERROR_RECORD)) == (EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_HARDWARE_ERROR_RECORD)) {
4051       mVariableModuleGlobal->HwErrVariableTotalSize += VariableSize;
4052     } else {
4053       mVariableModuleGlobal->CommonVariableTotalSize += VariableSize;
4054     }
4055 
4056     Variable = NextVariable;
4057   }
4058   mVariableModuleGlobal->NonVolatileLastVariableOffset = (UINTN) Variable - (UINTN) mNvVariableCache;
4059 
4060   return EFI_SUCCESS;
4061 }
4062 
4063 /**
4064   Flush the HOB variable to flash.
4065 
4066   @param[in] VariableName       Name of variable has been updated or deleted.
4067   @param[in] VendorGuid         Guid of variable has been updated or deleted.
4068 
4069 **/
4070 VOID
FlushHobVariableToFlash(IN CHAR16 * VariableName,IN EFI_GUID * VendorGuid)4071 FlushHobVariableToFlash (
4072   IN CHAR16                     *VariableName,
4073   IN EFI_GUID                   *VendorGuid
4074   )
4075 {
4076   EFI_STATUS                    Status;
4077   VARIABLE_STORE_HEADER         *VariableStoreHeader;
4078   VARIABLE_HEADER               *Variable;
4079   VOID                          *VariableData;
4080   VARIABLE_POINTER_TRACK        VariablePtrTrack;
4081   BOOLEAN                       ErrorFlag;
4082 
4083   ErrorFlag = FALSE;
4084 
4085   //
4086   // Flush the HOB variable to flash.
4087   //
4088   if (mVariableModuleGlobal->VariableGlobal.HobVariableBase != 0) {
4089     VariableStoreHeader = (VARIABLE_STORE_HEADER *) (UINTN) mVariableModuleGlobal->VariableGlobal.HobVariableBase;
4090     //
4091     // Set HobVariableBase to 0, it can avoid SetVariable to call back.
4092     //
4093     mVariableModuleGlobal->VariableGlobal.HobVariableBase = 0;
4094     for ( Variable = GetStartPointer (VariableStoreHeader)
4095         ; IsValidVariableHeader (Variable, GetEndPointer (VariableStoreHeader))
4096         ; Variable = GetNextVariablePtr (Variable)
4097         ) {
4098       if (Variable->State != VAR_ADDED) {
4099         //
4100         // The HOB variable has been set to DELETED state in local.
4101         //
4102         continue;
4103       }
4104       ASSERT ((Variable->Attributes & EFI_VARIABLE_NON_VOLATILE) != 0);
4105       if (VendorGuid == NULL || VariableName == NULL ||
4106           !CompareGuid (VendorGuid, GetVendorGuidPtr (Variable)) ||
4107           StrCmp (VariableName, GetVariableNamePtr (Variable)) != 0) {
4108         VariableData = GetVariableDataPtr (Variable);
4109         FindVariable (GetVariableNamePtr (Variable), GetVendorGuidPtr (Variable), &VariablePtrTrack, &mVariableModuleGlobal->VariableGlobal, FALSE);
4110         Status = UpdateVariable (
4111                    GetVariableNamePtr (Variable),
4112                    GetVendorGuidPtr (Variable),
4113                    VariableData,
4114                    DataSizeOfVariable (Variable),
4115                    Variable->Attributes,
4116                    0,
4117                    0,
4118                    &VariablePtrTrack,
4119                    NULL
4120                  );
4121         DEBUG ((EFI_D_INFO, "Variable driver flush the HOB variable to flash: %g %s %r\n", GetVendorGuidPtr (Variable), GetVariableNamePtr (Variable), Status));
4122       } else {
4123         //
4124         // The updated or deleted variable is matched with this HOB variable.
4125         // Don't break here because we will try to set other HOB variables
4126         // since this variable could be set successfully.
4127         //
4128         Status = EFI_SUCCESS;
4129       }
4130       if (!EFI_ERROR (Status)) {
4131         //
4132         // If set variable successful, or the updated or deleted variable is matched with the HOB variable,
4133         // set the HOB variable to DELETED state in local.
4134         //
4135         DEBUG ((EFI_D_INFO, "Variable driver set the HOB variable to DELETED state in local: %g %s\n", GetVendorGuidPtr (Variable), GetVariableNamePtr (Variable)));
4136         Variable->State &= VAR_DELETED;
4137       } else {
4138         ErrorFlag = TRUE;
4139       }
4140     }
4141     if (ErrorFlag) {
4142       //
4143       // We still have HOB variable(s) not flushed in flash.
4144       //
4145       mVariableModuleGlobal->VariableGlobal.HobVariableBase = (EFI_PHYSICAL_ADDRESS) (UINTN) VariableStoreHeader;
4146     } else {
4147       //
4148       // All HOB variables have been flushed in flash.
4149       //
4150       DEBUG ((EFI_D_INFO, "Variable driver: all HOB variables have been flushed in flash.\n"));
4151       if (!AtRuntime ()) {
4152         FreePool ((VOID *) VariableStoreHeader);
4153       }
4154     }
4155   }
4156 
4157 }
4158 
4159 /**
4160   Initializes variable write service.
4161 
4162   @retval EFI_SUCCESS          Function successfully executed.
4163   @retval Others               Fail to initialize the variable service.
4164 
4165 **/
4166 EFI_STATUS
VariableWriteServiceInitialize(VOID)4167 VariableWriteServiceInitialize (
4168   VOID
4169   )
4170 {
4171   EFI_STATUS                      Status;
4172   UINTN                           Index;
4173   UINT8                           Data;
4174   VARIABLE_ENTRY_PROPERTY         *VariableEntry;
4175 
4176   AcquireLockOnlyAtBootTime(&mVariableModuleGlobal->VariableGlobal.VariableServicesLock);
4177 
4178   //
4179   // Check if the free area is really free.
4180   //
4181   for (Index = mVariableModuleGlobal->NonVolatileLastVariableOffset; Index < mNvVariableCache->Size; Index++) {
4182     Data = ((UINT8 *) mNvVariableCache)[Index];
4183     if (Data != 0xff) {
4184       //
4185       // There must be something wrong in variable store, do reclaim operation.
4186       //
4187       Status = Reclaim (
4188                  mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase,
4189                  &mVariableModuleGlobal->NonVolatileLastVariableOffset,
4190                  FALSE,
4191                  NULL,
4192                  NULL,
4193                  0
4194                  );
4195       if (EFI_ERROR (Status)) {
4196         ReleaseLockOnlyAtBootTime (&mVariableModuleGlobal->VariableGlobal.VariableServicesLock);
4197         return Status;
4198       }
4199       break;
4200     }
4201   }
4202 
4203   FlushHobVariableToFlash (NULL, NULL);
4204 
4205   Status = EFI_SUCCESS;
4206   ZeroMem (&mAuthContextOut, sizeof (mAuthContextOut));
4207   if (mVariableModuleGlobal->VariableGlobal.AuthFormat) {
4208     //
4209     // Authenticated variable initialize.
4210     //
4211     mAuthContextIn.StructSize = sizeof (AUTH_VAR_LIB_CONTEXT_IN);
4212     mAuthContextIn.MaxAuthVariableSize = mVariableModuleGlobal->MaxAuthVariableSize - GetVariableHeaderSize ();
4213     Status = AuthVariableLibInitialize (&mAuthContextIn, &mAuthContextOut);
4214     if (!EFI_ERROR (Status)) {
4215       DEBUG ((EFI_D_INFO, "Variable driver will work with auth variable support!\n"));
4216       mVariableModuleGlobal->VariableGlobal.AuthSupport = TRUE;
4217       if (mAuthContextOut.AuthVarEntry != NULL) {
4218         for (Index = 0; Index < mAuthContextOut.AuthVarEntryCount; Index++) {
4219           VariableEntry = &mAuthContextOut.AuthVarEntry[Index];
4220           Status = VarCheckLibVariablePropertySet (
4221                      VariableEntry->Name,
4222                      VariableEntry->Guid,
4223                      &VariableEntry->VariableProperty
4224                      );
4225           ASSERT_EFI_ERROR (Status);
4226         }
4227       }
4228     } else if (Status == EFI_UNSUPPORTED) {
4229       DEBUG ((EFI_D_INFO, "NOTICE - AuthVariableLibInitialize() returns %r!\n", Status));
4230       DEBUG ((EFI_D_INFO, "Variable driver will continue to work without auth variable support!\n"));
4231       mVariableModuleGlobal->VariableGlobal.AuthSupport = FALSE;
4232       Status = EFI_SUCCESS;
4233     }
4234   }
4235 
4236   if (!EFI_ERROR (Status)) {
4237     for (Index = 0; Index < ARRAY_SIZE (mVariableEntryProperty); Index++) {
4238       VariableEntry = &mVariableEntryProperty[Index];
4239       Status = VarCheckLibVariablePropertySet (VariableEntry->Name, VariableEntry->Guid, &VariableEntry->VariableProperty);
4240       ASSERT_EFI_ERROR (Status);
4241     }
4242   }
4243 
4244   ReleaseLockOnlyAtBootTime (&mVariableModuleGlobal->VariableGlobal.VariableServicesLock);
4245 
4246   //
4247   // Initialize MOR Lock variable.
4248   //
4249   MorLockInit ();
4250 
4251   return Status;
4252 }
4253 
4254 /**
4255   Convert normal variable storage to the allocated auth variable storage.
4256 
4257   @param[in]  NormalVarStorage  Pointer to the normal variable storage header
4258 
4259   @retval the allocated auth variable storage
4260 **/
4261 VOID *
ConvertNormalVarStorageToAuthVarStorage(VARIABLE_STORE_HEADER * NormalVarStorage)4262 ConvertNormalVarStorageToAuthVarStorage (
4263   VARIABLE_STORE_HEADER *NormalVarStorage
4264   )
4265 {
4266   VARIABLE_HEADER *StartPtr;
4267   UINT8           *NextPtr;
4268   VARIABLE_HEADER *EndPtr;
4269   UINTN           AuthVarStroageSize;
4270   AUTHENTICATED_VARIABLE_HEADER *AuthStartPtr;
4271   VARIABLE_STORE_HEADER         *AuthVarStorage;
4272 
4273   AuthVarStroageSize  = sizeof (VARIABLE_STORE_HEADER);
4274   //
4275   // Set AuthFormat as FALSE for normal variable storage
4276   //
4277   mVariableModuleGlobal->VariableGlobal.AuthFormat = FALSE;
4278 
4279   //
4280   // Calculate Auth Variable Storage Size
4281   //
4282   StartPtr = GetStartPointer (NormalVarStorage);
4283   EndPtr   = GetEndPointer (NormalVarStorage);
4284   while (StartPtr < EndPtr) {
4285     if (StartPtr->State == VAR_ADDED) {
4286       AuthVarStroageSize = HEADER_ALIGN (AuthVarStroageSize);
4287       AuthVarStroageSize += sizeof (AUTHENTICATED_VARIABLE_HEADER);
4288       AuthVarStroageSize += StartPtr->NameSize + GET_PAD_SIZE (StartPtr->NameSize);
4289       AuthVarStroageSize += StartPtr->DataSize + GET_PAD_SIZE (StartPtr->DataSize);
4290     }
4291     StartPtr  = GetNextVariablePtr (StartPtr);
4292   }
4293 
4294   //
4295   // Allocate Runtime memory for Auth Variable Storage
4296   //
4297   AuthVarStorage = AllocateRuntimeZeroPool (AuthVarStroageSize);
4298   ASSERT (AuthVarStorage != NULL);
4299   if (AuthVarStorage == NULL) {
4300     return NULL;
4301   }
4302 
4303   //
4304   // Copy Variable from Normal storage to Auth storage
4305   //
4306   StartPtr = GetStartPointer (NormalVarStorage);
4307   EndPtr   = GetEndPointer (NormalVarStorage);
4308   AuthStartPtr = (AUTHENTICATED_VARIABLE_HEADER *) GetStartPointer (AuthVarStorage);
4309   while (StartPtr < EndPtr) {
4310     if (StartPtr->State == VAR_ADDED) {
4311       AuthStartPtr = (AUTHENTICATED_VARIABLE_HEADER *) HEADER_ALIGN (AuthStartPtr);
4312       //
4313       // Copy Variable Header
4314       //
4315       AuthStartPtr->StartId     = StartPtr->StartId;
4316       AuthStartPtr->State       = StartPtr->State;
4317       AuthStartPtr->Attributes  = StartPtr->Attributes;
4318       AuthStartPtr->NameSize    = StartPtr->NameSize;
4319       AuthStartPtr->DataSize    = StartPtr->DataSize;
4320       CopyGuid (&AuthStartPtr->VendorGuid, &StartPtr->VendorGuid);
4321       //
4322       // Copy Variable Name
4323       //
4324       NextPtr = (UINT8 *) (AuthStartPtr + 1);
4325       CopyMem (NextPtr, GetVariableNamePtr (StartPtr), AuthStartPtr->NameSize);
4326       //
4327       // Copy Variable Data
4328       //
4329       NextPtr = NextPtr + AuthStartPtr->NameSize + GET_PAD_SIZE (AuthStartPtr->NameSize);
4330       CopyMem (NextPtr, GetVariableDataPtr (StartPtr), AuthStartPtr->DataSize);
4331       //
4332       // Go to next variable
4333       //
4334       AuthStartPtr = (AUTHENTICATED_VARIABLE_HEADER *) (NextPtr + AuthStartPtr->DataSize + GET_PAD_SIZE (AuthStartPtr->DataSize));
4335     }
4336     StartPtr = GetNextVariablePtr (StartPtr);
4337   }
4338   //
4339   // Update Auth Storage Header
4340   //
4341   AuthVarStorage->Format = NormalVarStorage->Format;
4342   AuthVarStorage->State  = NormalVarStorage->State;
4343   AuthVarStorage->Size = (UINT32)((UINTN)AuthStartPtr - (UINTN)AuthVarStorage);
4344   CopyGuid (&AuthVarStorage->Signature, &gEfiAuthenticatedVariableGuid);
4345   ASSERT (AuthVarStorage->Size <= AuthVarStroageSize);
4346 
4347   //
4348   // Restore AuthFormat
4349   //
4350   mVariableModuleGlobal->VariableGlobal.AuthFormat = TRUE;
4351   return AuthVarStorage;
4352 }
4353 
4354 /**
4355   Get HOB variable store.
4356 
4357   @param[in] VariableGuid       NV variable store signature.
4358 
4359   @retval EFI_SUCCESS           Function successfully executed.
4360   @retval EFI_OUT_OF_RESOURCES  Fail to allocate enough memory resource.
4361 
4362 **/
4363 EFI_STATUS
GetHobVariableStore(IN EFI_GUID * VariableGuid)4364 GetHobVariableStore (
4365   IN EFI_GUID                   *VariableGuid
4366   )
4367 {
4368   VARIABLE_STORE_HEADER         *VariableStoreHeader;
4369   UINT64                        VariableStoreLength;
4370   EFI_HOB_GUID_TYPE             *GuidHob;
4371   BOOLEAN                       NeedConvertNormalToAuth;
4372 
4373   //
4374   // Make sure there is no more than one Variable HOB.
4375   //
4376   DEBUG_CODE (
4377     GuidHob = GetFirstGuidHob (&gEfiAuthenticatedVariableGuid);
4378     if (GuidHob != NULL) {
4379       if ((GetNextGuidHob (&gEfiAuthenticatedVariableGuid, GET_NEXT_HOB (GuidHob)) != NULL)) {
4380         DEBUG ((DEBUG_ERROR, "ERROR: Found two Auth Variable HOBs\n"));
4381         ASSERT (FALSE);
4382       } else if (GetFirstGuidHob (&gEfiVariableGuid) != NULL) {
4383         DEBUG ((DEBUG_ERROR, "ERROR: Found one Auth + one Normal Variable HOBs\n"));
4384         ASSERT (FALSE);
4385       }
4386     } else {
4387       GuidHob = GetFirstGuidHob (&gEfiVariableGuid);
4388       if (GuidHob != NULL) {
4389         if ((GetNextGuidHob (&gEfiVariableGuid, GET_NEXT_HOB (GuidHob)) != NULL)) {
4390           DEBUG ((DEBUG_ERROR, "ERROR: Found two Normal Variable HOBs\n"));
4391           ASSERT (FALSE);
4392         }
4393       }
4394     }
4395   );
4396 
4397   //
4398   // Combinations supported:
4399   // 1. Normal NV variable store +
4400   //    Normal HOB variable store
4401   // 2. Auth NV variable store +
4402   //    Auth HOB variable store
4403   // 3. Auth NV variable store +
4404   //    Normal HOB variable store (code will convert it to Auth Format)
4405   //
4406   NeedConvertNormalToAuth = FALSE;
4407   GuidHob = GetFirstGuidHob (VariableGuid);
4408   if (GuidHob == NULL && VariableGuid == &gEfiAuthenticatedVariableGuid) {
4409     //
4410     // Try getting it from normal variable HOB
4411     //
4412     GuidHob = GetFirstGuidHob (&gEfiVariableGuid);
4413     NeedConvertNormalToAuth = TRUE;
4414   }
4415   if (GuidHob != NULL) {
4416     VariableStoreHeader = GET_GUID_HOB_DATA (GuidHob);
4417     VariableStoreLength = GuidHob->Header.HobLength - sizeof (EFI_HOB_GUID_TYPE);
4418     if (GetVariableStoreStatus (VariableStoreHeader) == EfiValid) {
4419       if (!NeedConvertNormalToAuth) {
4420         mVariableModuleGlobal->VariableGlobal.HobVariableBase = (EFI_PHYSICAL_ADDRESS) (UINTN) AllocateRuntimeCopyPool ((UINTN) VariableStoreLength, (VOID *) VariableStoreHeader);
4421       } else {
4422         mVariableModuleGlobal->VariableGlobal.HobVariableBase = (EFI_PHYSICAL_ADDRESS) (UINTN) ConvertNormalVarStorageToAuthVarStorage ((VOID *) VariableStoreHeader);
4423       }
4424       if (mVariableModuleGlobal->VariableGlobal.HobVariableBase == 0) {
4425         return EFI_OUT_OF_RESOURCES;
4426       }
4427     } else {
4428       DEBUG ((EFI_D_ERROR, "HOB Variable Store header is corrupted!\n"));
4429     }
4430   }
4431 
4432   return EFI_SUCCESS;
4433 }
4434 
4435 /**
4436   Initializes variable store area for non-volatile and volatile variable.
4437 
4438   @retval EFI_SUCCESS           Function successfully executed.
4439   @retval EFI_OUT_OF_RESOURCES  Fail to allocate enough memory resource.
4440 
4441 **/
4442 EFI_STATUS
VariableCommonInitialize(VOID)4443 VariableCommonInitialize (
4444   VOID
4445   )
4446 {
4447   EFI_STATUS                      Status;
4448   VARIABLE_STORE_HEADER           *VolatileVariableStore;
4449   UINTN                           ScratchSize;
4450   EFI_GUID                        *VariableGuid;
4451 
4452   //
4453   // Allocate runtime memory for variable driver global structure.
4454   //
4455   mVariableModuleGlobal = AllocateRuntimeZeroPool (sizeof (VARIABLE_MODULE_GLOBAL));
4456   if (mVariableModuleGlobal == NULL) {
4457     return EFI_OUT_OF_RESOURCES;
4458   }
4459 
4460   InitializeLock (&mVariableModuleGlobal->VariableGlobal.VariableServicesLock, TPL_NOTIFY);
4461 
4462   //
4463   // Init non-volatile variable store.
4464   //
4465   Status = InitNonVolatileVariableStore ();
4466   if (EFI_ERROR (Status)) {
4467     FreePool (mVariableModuleGlobal);
4468     return Status;
4469   }
4470 
4471   //
4472   // mVariableModuleGlobal->VariableGlobal.AuthFormat
4473   // has been initialized in InitNonVolatileVariableStore().
4474   //
4475   if (mVariableModuleGlobal->VariableGlobal.AuthFormat) {
4476     DEBUG ((EFI_D_INFO, "Variable driver will work with auth variable format!\n"));
4477     //
4478     // Set AuthSupport to FALSE first, VariableWriteServiceInitialize() will initialize it.
4479     //
4480     mVariableModuleGlobal->VariableGlobal.AuthSupport = FALSE;
4481     VariableGuid = &gEfiAuthenticatedVariableGuid;
4482   } else {
4483     DEBUG ((EFI_D_INFO, "Variable driver will work without auth variable support!\n"));
4484     mVariableModuleGlobal->VariableGlobal.AuthSupport = FALSE;
4485     VariableGuid = &gEfiVariableGuid;
4486   }
4487 
4488   //
4489   // Get HOB variable store.
4490   //
4491   Status = GetHobVariableStore (VariableGuid);
4492   if (EFI_ERROR (Status)) {
4493     if (mNvFvHeaderCache != NULL) {
4494       FreePool (mNvFvHeaderCache);
4495     }
4496     FreePool (mVariableModuleGlobal);
4497     return Status;
4498   }
4499 
4500   mVariableModuleGlobal->MaxVolatileVariableSize = ((PcdGet32 (PcdMaxVolatileVariableSize) != 0) ?
4501                                                     PcdGet32 (PcdMaxVolatileVariableSize) :
4502                                                     mVariableModuleGlobal->MaxVariableSize
4503                                                     );
4504   //
4505   // Allocate memory for volatile variable store, note that there is a scratch space to store scratch data.
4506   //
4507   ScratchSize = GetMaxVariableSize ();
4508   mVariableModuleGlobal->ScratchBufferSize = ScratchSize;
4509   VolatileVariableStore = AllocateRuntimePool (PcdGet32 (PcdVariableStoreSize) + ScratchSize);
4510   if (VolatileVariableStore == NULL) {
4511     if (mVariableModuleGlobal->VariableGlobal.HobVariableBase != 0) {
4512       FreePool ((VOID *) (UINTN) mVariableModuleGlobal->VariableGlobal.HobVariableBase);
4513     }
4514     if (mNvFvHeaderCache != NULL) {
4515       FreePool (mNvFvHeaderCache);
4516     }
4517     FreePool (mVariableModuleGlobal);
4518     return EFI_OUT_OF_RESOURCES;
4519   }
4520 
4521   SetMem (VolatileVariableStore, PcdGet32 (PcdVariableStoreSize) + ScratchSize, 0xff);
4522 
4523   //
4524   // Initialize Variable Specific Data.
4525   //
4526   mVariableModuleGlobal->VariableGlobal.VolatileVariableBase = (EFI_PHYSICAL_ADDRESS) (UINTN) VolatileVariableStore;
4527   mVariableModuleGlobal->VolatileLastVariableOffset = (UINTN) GetStartPointer (VolatileVariableStore) - (UINTN) VolatileVariableStore;
4528 
4529   CopyGuid (&VolatileVariableStore->Signature, VariableGuid);
4530   VolatileVariableStore->Size        = PcdGet32 (PcdVariableStoreSize);
4531   VolatileVariableStore->Format      = VARIABLE_STORE_FORMATTED;
4532   VolatileVariableStore->State       = VARIABLE_STORE_HEALTHY;
4533   VolatileVariableStore->Reserved    = 0;
4534   VolatileVariableStore->Reserved1   = 0;
4535 
4536   return EFI_SUCCESS;
4537 }
4538 
4539 
4540 /**
4541   Get the proper fvb handle and/or fvb protocol by the given Flash address.
4542 
4543   @param[in]  Address       The Flash address.
4544   @param[out] FvbHandle     In output, if it is not NULL, it points to the proper FVB handle.
4545   @param[out] FvbProtocol   In output, if it is not NULL, it points to the proper FVB protocol.
4546 
4547 **/
4548 EFI_STATUS
GetFvbInfoByAddress(IN EFI_PHYSICAL_ADDRESS Address,OUT EFI_HANDLE * FvbHandle OPTIONAL,OUT EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL ** FvbProtocol OPTIONAL)4549 GetFvbInfoByAddress (
4550   IN  EFI_PHYSICAL_ADDRESS                Address,
4551   OUT EFI_HANDLE                          *FvbHandle OPTIONAL,
4552   OUT EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL  **FvbProtocol OPTIONAL
4553   )
4554 {
4555   EFI_STATUS                              Status;
4556   EFI_HANDLE                              *HandleBuffer;
4557   UINTN                                   HandleCount;
4558   UINTN                                   Index;
4559   EFI_PHYSICAL_ADDRESS                    FvbBaseAddress;
4560   EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL      *Fvb;
4561   EFI_FVB_ATTRIBUTES_2                    Attributes;
4562   UINTN                                   BlockSize;
4563   UINTN                                   NumberOfBlocks;
4564 
4565   HandleBuffer = NULL;
4566   //
4567   // Get all FVB handles.
4568   //
4569   Status = GetFvbCountAndBuffer (&HandleCount, &HandleBuffer);
4570   if (EFI_ERROR (Status)) {
4571     return EFI_NOT_FOUND;
4572   }
4573 
4574   //
4575   // Get the FVB to access variable store.
4576   //
4577   Fvb = NULL;
4578   for (Index = 0; Index < HandleCount; Index += 1, Status = EFI_NOT_FOUND, Fvb = NULL) {
4579     Status = GetFvbByHandle (HandleBuffer[Index], &Fvb);
4580     if (EFI_ERROR (Status)) {
4581       Status = EFI_NOT_FOUND;
4582       break;
4583     }
4584 
4585     //
4586     // Ensure this FVB protocol supported Write operation.
4587     //
4588     Status = Fvb->GetAttributes (Fvb, &Attributes);
4589     if (EFI_ERROR (Status) || ((Attributes & EFI_FVB2_WRITE_STATUS) == 0)) {
4590       continue;
4591     }
4592 
4593     //
4594     // Compare the address and select the right one.
4595     //
4596     Status = Fvb->GetPhysicalAddress (Fvb, &FvbBaseAddress);
4597     if (EFI_ERROR (Status)) {
4598       continue;
4599     }
4600 
4601     //
4602     // Assume one FVB has one type of BlockSize.
4603     //
4604     Status = Fvb->GetBlockSize (Fvb, 0, &BlockSize, &NumberOfBlocks);
4605     if (EFI_ERROR (Status)) {
4606       continue;
4607     }
4608 
4609     if ((Address >= FvbBaseAddress) && (Address < (FvbBaseAddress + BlockSize * NumberOfBlocks))) {
4610       if (FvbHandle != NULL) {
4611         *FvbHandle  = HandleBuffer[Index];
4612       }
4613       if (FvbProtocol != NULL) {
4614         *FvbProtocol = Fvb;
4615       }
4616       Status = EFI_SUCCESS;
4617       break;
4618     }
4619   }
4620   FreePool (HandleBuffer);
4621 
4622   if (Fvb == NULL) {
4623     Status = EFI_NOT_FOUND;
4624   }
4625 
4626   return Status;
4627 }
4628 
4629