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