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