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