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