Home | History | Annotate | Download | only in EsalVariableDxeSal
      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
     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
     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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
   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
   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 *
   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 *
   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
   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
   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
   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
   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
   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
   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
   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
   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
   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