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