Home | History | Annotate | Download | only in RuntimeDxe
      1 /** @file
      2   Implement all four UEFI Runtime Variable services for the nonvolatile
      3   and volatile storage space and install variable architecture protocol
      4   based on SMM variable module.
      5 
      6   Caution: This module requires additional review when modified.
      7   This driver will have external input - variable data.
      8   This external input must be validated carefully to avoid security issue like
      9   buffer overflow, integer overflow.
     10 
     11   RuntimeServiceGetVariable() and RuntimeServiceSetVariable() are external API
     12   to receive data buffer. The size should be checked carefully.
     13 
     14   InitCommunicateBuffer() is really function to check the variable data size.
     15 
     16 Copyright (c) 2010 - 2015, Intel Corporation. All rights reserved.<BR>
     17 This program and the accompanying materials
     18 are licensed and made available under the terms and conditions of the BSD License
     19 which accompanies this distribution.  The full text of the license may be found at
     20 http://opensource.org/licenses/bsd-license.php
     21 
     22 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
     23 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
     24 
     25 **/
     26 #include <PiDxe.h>
     27 #include <Protocol/VariableWrite.h>
     28 #include <Protocol/Variable.h>
     29 #include <Protocol/SmmCommunication.h>
     30 #include <Protocol/SmmVariable.h>
     31 #include <Protocol/VariableLock.h>
     32 #include <Protocol/VarCheck.h>
     33 
     34 #include <Library/UefiBootServicesTableLib.h>
     35 #include <Library/UefiRuntimeServicesTableLib.h>
     36 #include <Library/MemoryAllocationLib.h>
     37 #include <Library/UefiDriverEntryPoint.h>
     38 #include <Library/UefiRuntimeLib.h>
     39 #include <Library/BaseMemoryLib.h>
     40 #include <Library/DebugLib.h>
     41 #include <Library/UefiLib.h>
     42 #include <Library/BaseLib.h>
     43 
     44 #include <Guid/EventGroup.h>
     45 #include <Guid/SmmVariableCommon.h>
     46 
     47 EFI_HANDLE                       mHandle                    = NULL;
     48 EFI_SMM_VARIABLE_PROTOCOL       *mSmmVariable               = NULL;
     49 EFI_EVENT                        mVirtualAddressChangeEvent = NULL;
     50 EFI_SMM_COMMUNICATION_PROTOCOL  *mSmmCommunication          = NULL;
     51 UINT8                           *mVariableBuffer            = NULL;
     52 UINT8                           *mVariableBufferPhysical    = NULL;
     53 UINTN                            mVariableBufferSize;
     54 UINTN                            mVariableBufferPayloadSize;
     55 EFI_LOCK                         mVariableServicesLock;
     56 EDKII_VARIABLE_LOCK_PROTOCOL     mVariableLock;
     57 EDKII_VAR_CHECK_PROTOCOL         mVarCheck;
     58 
     59 /**
     60   SecureBoot Hook for SetVariable.
     61 
     62   @param[in] VariableName                 Name of Variable to be found.
     63   @param[in] VendorGuid                   Variable vendor GUID.
     64 
     65 **/
     66 VOID
     67 EFIAPI
     68 SecureBootHook (
     69   IN CHAR16                                 *VariableName,
     70   IN EFI_GUID                               *VendorGuid
     71   );
     72 
     73 /**
     74   Acquires lock only at boot time. Simply returns at runtime.
     75 
     76   This is a temperary function that will be removed when
     77   EfiAcquireLock() in UefiLib can handle the call in UEFI
     78   Runtimer driver in RT phase.
     79   It calls EfiAcquireLock() at boot time, and simply returns
     80   at runtime.
     81 
     82   @param  Lock         A pointer to the lock to acquire.
     83 
     84 **/
     85 VOID
     86 AcquireLockOnlyAtBootTime (
     87   IN EFI_LOCK                             *Lock
     88   )
     89 {
     90   if (!EfiAtRuntime ()) {
     91     EfiAcquireLock (Lock);
     92   }
     93 }
     94 
     95 /**
     96   Releases lock only at boot time. Simply returns at runtime.
     97 
     98   This is a temperary function which will be removed when
     99   EfiReleaseLock() in UefiLib can handle the call in UEFI
    100   Runtimer driver in RT phase.
    101   It calls EfiReleaseLock() at boot time and simply returns
    102   at runtime.
    103 
    104   @param  Lock         A pointer to the lock to release.
    105 
    106 **/
    107 VOID
    108 ReleaseLockOnlyAtBootTime (
    109   IN EFI_LOCK                             *Lock
    110   )
    111 {
    112   if (!EfiAtRuntime ()) {
    113     EfiReleaseLock (Lock);
    114   }
    115 }
    116 
    117 /**
    118   Initialize the communicate buffer using DataSize and Function.
    119 
    120   The communicate size is: SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE +
    121   DataSize.
    122 
    123   Caution: This function may receive untrusted input.
    124   The data size external input, so this function will validate it carefully to avoid buffer overflow.
    125 
    126   @param[out]      DataPtr          Points to the data in the communicate buffer.
    127   @param[in]       DataSize         The data size to send to SMM.
    128   @param[in]       Function         The function number to initialize the communicate header.
    129 
    130   @retval EFI_INVALID_PARAMETER     The data size is too big.
    131   @retval EFI_SUCCESS               Find the specified variable.
    132 
    133 **/
    134 EFI_STATUS
    135 InitCommunicateBuffer (
    136   OUT     VOID                              **DataPtr OPTIONAL,
    137   IN      UINTN                             DataSize,
    138   IN      UINTN                             Function
    139   )
    140 {
    141   EFI_SMM_COMMUNICATE_HEADER                *SmmCommunicateHeader;
    142   SMM_VARIABLE_COMMUNICATE_HEADER           *SmmVariableFunctionHeader;
    143 
    144 
    145   if (DataSize + SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE > mVariableBufferSize) {
    146     return EFI_INVALID_PARAMETER;
    147   }
    148 
    149   SmmCommunicateHeader = (EFI_SMM_COMMUNICATE_HEADER *) mVariableBuffer;
    150   CopyGuid (&SmmCommunicateHeader->HeaderGuid, &gEfiSmmVariableProtocolGuid);
    151   SmmCommunicateHeader->MessageLength = DataSize + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE;
    152 
    153   SmmVariableFunctionHeader = (SMM_VARIABLE_COMMUNICATE_HEADER *) SmmCommunicateHeader->Data;
    154   SmmVariableFunctionHeader->Function = Function;
    155   if (DataPtr != NULL) {
    156     *DataPtr = SmmVariableFunctionHeader->Data;
    157   }
    158 
    159   return EFI_SUCCESS;
    160 }
    161 
    162 
    163 /**
    164   Send the data in communicate buffer to SMM.
    165 
    166   @param[in]   DataSize               This size of the function header and the data.
    167 
    168   @retval      EFI_SUCCESS            Success is returned from the functin in SMM.
    169   @retval      Others                 Failure is returned from the function in SMM.
    170 
    171 **/
    172 EFI_STATUS
    173 SendCommunicateBuffer (
    174   IN      UINTN                             DataSize
    175   )
    176 {
    177   EFI_STATUS                                Status;
    178   UINTN                                     CommSize;
    179   EFI_SMM_COMMUNICATE_HEADER                *SmmCommunicateHeader;
    180   SMM_VARIABLE_COMMUNICATE_HEADER           *SmmVariableFunctionHeader;
    181 
    182   CommSize = DataSize + SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE;
    183   Status = mSmmCommunication->Communicate (mSmmCommunication, mVariableBufferPhysical, &CommSize);
    184   ASSERT_EFI_ERROR (Status);
    185 
    186   SmmCommunicateHeader      = (EFI_SMM_COMMUNICATE_HEADER *) mVariableBuffer;
    187   SmmVariableFunctionHeader = (SMM_VARIABLE_COMMUNICATE_HEADER *)SmmCommunicateHeader->Data;
    188   return  SmmVariableFunctionHeader->ReturnStatus;
    189 }
    190 
    191 /**
    192   Mark a variable that will become read-only after leaving the DXE phase of execution.
    193 
    194   @param[in] This          The VARIABLE_LOCK_PROTOCOL instance.
    195   @param[in] VariableName  A pointer to the variable name that will be made read-only subsequently.
    196   @param[in] VendorGuid    A pointer to the vendor GUID that will be made read-only subsequently.
    197 
    198   @retval EFI_SUCCESS           The variable specified by the VariableName and the VendorGuid was marked
    199                                 as pending to be read-only.
    200   @retval EFI_INVALID_PARAMETER VariableName or VendorGuid is NULL.
    201                                 Or VariableName is an empty string.
    202   @retval EFI_ACCESS_DENIED     EFI_END_OF_DXE_EVENT_GROUP_GUID or EFI_EVENT_GROUP_READY_TO_BOOT has
    203                                 already been signaled.
    204   @retval EFI_OUT_OF_RESOURCES  There is not enough resource to hold the lock request.
    205 **/
    206 EFI_STATUS
    207 EFIAPI
    208 VariableLockRequestToLock (
    209   IN CONST EDKII_VARIABLE_LOCK_PROTOCOL *This,
    210   IN       CHAR16                       *VariableName,
    211   IN       EFI_GUID                     *VendorGuid
    212   )
    213 {
    214   EFI_STATUS                                Status;
    215   UINTN                                     VariableNameSize;
    216   UINTN                                     PayloadSize;
    217   SMM_VARIABLE_COMMUNICATE_LOCK_VARIABLE    *VariableToLock;
    218 
    219   if (VariableName == NULL || VariableName[0] == 0 || VendorGuid == NULL) {
    220     return EFI_INVALID_PARAMETER;
    221   }
    222 
    223   VariableNameSize = StrSize (VariableName);
    224   VariableToLock   = NULL;
    225 
    226   //
    227   // If VariableName exceeds SMM payload limit. Return failure
    228   //
    229   if (VariableNameSize > mVariableBufferPayloadSize - OFFSET_OF (SMM_VARIABLE_COMMUNICATE_LOCK_VARIABLE, Name)) {
    230     return EFI_INVALID_PARAMETER;
    231   }
    232 
    233   AcquireLockOnlyAtBootTime(&mVariableServicesLock);
    234 
    235   //
    236   // Init the communicate buffer. The buffer data size is:
    237   // SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + PayloadSize.
    238   //
    239   PayloadSize = OFFSET_OF (SMM_VARIABLE_COMMUNICATE_LOCK_VARIABLE, Name) + VariableNameSize;
    240   Status = InitCommunicateBuffer ((VOID **) &VariableToLock, PayloadSize, SMM_VARIABLE_FUNCTION_LOCK_VARIABLE);
    241   if (EFI_ERROR (Status)) {
    242     goto Done;
    243   }
    244   ASSERT (VariableToLock != NULL);
    245 
    246   CopyGuid (&VariableToLock->Guid, VendorGuid);
    247   VariableToLock->NameSize = VariableNameSize;
    248   CopyMem (VariableToLock->Name, VariableName, VariableToLock->NameSize);
    249 
    250   //
    251   // Send data to SMM.
    252   //
    253   Status = SendCommunicateBuffer (PayloadSize);
    254 
    255 Done:
    256   ReleaseLockOnlyAtBootTime (&mVariableServicesLock);
    257   return Status;
    258 }
    259 
    260 /**
    261   Register SetVariable check handler.
    262 
    263   @param[in] Handler            Pointer to check handler.
    264 
    265   @retval EFI_SUCCESS           The SetVariable check handler was registered successfully.
    266   @retval EFI_INVALID_PARAMETER Handler is NULL.
    267   @retval EFI_ACCESS_DENIED     EFI_END_OF_DXE_EVENT_GROUP_GUID or EFI_EVENT_GROUP_READY_TO_BOOT has
    268                                 already been signaled.
    269   @retval EFI_OUT_OF_RESOURCES  There is not enough resource for the SetVariable check handler register request.
    270   @retval EFI_UNSUPPORTED       This interface is not implemented.
    271                                 For example, it is unsupported in VarCheck protocol if both VarCheck and SmmVarCheck protocols are present.
    272 
    273 **/
    274 EFI_STATUS
    275 EFIAPI
    276 VarCheckRegisterSetVariableCheckHandler (
    277   IN VAR_CHECK_SET_VARIABLE_CHECK_HANDLER   Handler
    278   )
    279 {
    280   return EFI_UNSUPPORTED;
    281 }
    282 
    283 /**
    284   Variable property set.
    285 
    286   @param[in] Name               Pointer to the variable name.
    287   @param[in] Guid               Pointer to the vendor GUID.
    288   @param[in] VariableProperty   Pointer to the input variable property.
    289 
    290   @retval EFI_SUCCESS           The property of variable specified by the Name and Guid was set successfully.
    291   @retval EFI_INVALID_PARAMETER Name, Guid or VariableProperty is NULL, or Name is an empty string,
    292                                 or the fields of VariableProperty are not valid.
    293   @retval EFI_ACCESS_DENIED     EFI_END_OF_DXE_EVENT_GROUP_GUID or EFI_EVENT_GROUP_READY_TO_BOOT has
    294                                 already been signaled.
    295   @retval EFI_OUT_OF_RESOURCES  There is not enough resource for the variable property set request.
    296 
    297 **/
    298 EFI_STATUS
    299 EFIAPI
    300 VarCheckVariablePropertySet (
    301   IN CHAR16                         *Name,
    302   IN EFI_GUID                       *Guid,
    303   IN VAR_CHECK_VARIABLE_PROPERTY    *VariableProperty
    304   )
    305 {
    306   EFI_STATUS                                Status;
    307   UINTN                                     VariableNameSize;
    308   UINTN                                     PayloadSize;
    309   SMM_VARIABLE_COMMUNICATE_VAR_CHECK_VARIABLE_PROPERTY *CommVariableProperty;
    310 
    311   if (Name == NULL || Name[0] == 0 || Guid == NULL) {
    312     return EFI_INVALID_PARAMETER;
    313   }
    314 
    315   if (VariableProperty == NULL) {
    316     return EFI_INVALID_PARAMETER;
    317   }
    318 
    319   if (VariableProperty->Revision != VAR_CHECK_VARIABLE_PROPERTY_REVISION) {
    320     return EFI_INVALID_PARAMETER;
    321   }
    322 
    323   VariableNameSize = StrSize (Name);
    324   CommVariableProperty = NULL;
    325 
    326   //
    327   // If VariableName exceeds SMM payload limit. Return failure
    328   //
    329   if (VariableNameSize > mVariableBufferPayloadSize - OFFSET_OF (SMM_VARIABLE_COMMUNICATE_VAR_CHECK_VARIABLE_PROPERTY, Name)) {
    330     return EFI_INVALID_PARAMETER;
    331   }
    332 
    333   AcquireLockOnlyAtBootTime (&mVariableServicesLock);
    334 
    335   //
    336   // Init the communicate buffer. The buffer data size is:
    337   // SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + PayloadSize.
    338   //
    339   PayloadSize = OFFSET_OF (SMM_VARIABLE_COMMUNICATE_VAR_CHECK_VARIABLE_PROPERTY, Name) + VariableNameSize;
    340   Status = InitCommunicateBuffer ((VOID **) &CommVariableProperty, PayloadSize, SMM_VARIABLE_FUNCTION_VAR_CHECK_VARIABLE_PROPERTY_SET);
    341   if (EFI_ERROR (Status)) {
    342     goto Done;
    343   }
    344   ASSERT (CommVariableProperty != NULL);
    345 
    346   CopyGuid (&CommVariableProperty->Guid, Guid);
    347   CopyMem (&CommVariableProperty->VariableProperty, VariableProperty, sizeof (*VariableProperty));
    348   CommVariableProperty->NameSize = VariableNameSize;
    349   CopyMem (CommVariableProperty->Name, Name, CommVariableProperty->NameSize);
    350 
    351   //
    352   // Send data to SMM.
    353   //
    354   Status = SendCommunicateBuffer (PayloadSize);
    355 
    356 Done:
    357   ReleaseLockOnlyAtBootTime (&mVariableServicesLock);
    358   return Status;
    359 }
    360 
    361 /**
    362   Variable property get.
    363 
    364   @param[in]  Name              Pointer to the variable name.
    365   @param[in]  Guid              Pointer to the vendor GUID.
    366   @param[out] VariableProperty  Pointer to the output variable property.
    367 
    368   @retval EFI_SUCCESS           The property of variable specified by the Name and Guid was got successfully.
    369   @retval EFI_INVALID_PARAMETER Name, Guid or VariableProperty is NULL, or Name is an empty string.
    370   @retval EFI_NOT_FOUND         The property of variable specified by the Name and Guid was not found.
    371 
    372 **/
    373 EFI_STATUS
    374 EFIAPI
    375 VarCheckVariablePropertyGet (
    376   IN CHAR16                         *Name,
    377   IN EFI_GUID                       *Guid,
    378   OUT VAR_CHECK_VARIABLE_PROPERTY   *VariableProperty
    379   )
    380 {
    381   EFI_STATUS                                Status;
    382   UINTN                                     VariableNameSize;
    383   UINTN                                     PayloadSize;
    384   SMM_VARIABLE_COMMUNICATE_VAR_CHECK_VARIABLE_PROPERTY *CommVariableProperty;
    385 
    386   if (Name == NULL || Name[0] == 0 || Guid == NULL) {
    387     return EFI_INVALID_PARAMETER;
    388   }
    389 
    390   if (VariableProperty == NULL) {
    391     return EFI_INVALID_PARAMETER;
    392   }
    393 
    394   VariableNameSize = StrSize (Name);
    395   CommVariableProperty = NULL;
    396 
    397   //
    398   // If VariableName exceeds SMM payload limit. Return failure
    399   //
    400   if (VariableNameSize > mVariableBufferPayloadSize - OFFSET_OF (SMM_VARIABLE_COMMUNICATE_VAR_CHECK_VARIABLE_PROPERTY, Name)) {
    401     return EFI_INVALID_PARAMETER;
    402   }
    403 
    404   AcquireLockOnlyAtBootTime (&mVariableServicesLock);
    405 
    406   //
    407   // Init the communicate buffer. The buffer data size is:
    408   // SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + PayloadSize.
    409   //
    410   PayloadSize = OFFSET_OF (SMM_VARIABLE_COMMUNICATE_VAR_CHECK_VARIABLE_PROPERTY, Name) + VariableNameSize;
    411   Status = InitCommunicateBuffer ((VOID **) &CommVariableProperty, PayloadSize, SMM_VARIABLE_FUNCTION_VAR_CHECK_VARIABLE_PROPERTY_GET);
    412   if (EFI_ERROR (Status)) {
    413     goto Done;
    414   }
    415   ASSERT (CommVariableProperty != NULL);
    416 
    417   CopyGuid (&CommVariableProperty->Guid, Guid);
    418   CommVariableProperty->NameSize = VariableNameSize;
    419   CopyMem (CommVariableProperty->Name, Name, CommVariableProperty->NameSize);
    420 
    421   //
    422   // Send data to SMM.
    423   //
    424   Status = SendCommunicateBuffer (PayloadSize);
    425   if (Status == EFI_SUCCESS) {
    426     CopyMem (VariableProperty, &CommVariableProperty->VariableProperty, sizeof (*VariableProperty));
    427   }
    428 
    429 Done:
    430   ReleaseLockOnlyAtBootTime (&mVariableServicesLock);
    431   return Status;
    432 }
    433 
    434 /**
    435   This code finds variable in storage blocks (Volatile or Non-Volatile).
    436 
    437   Caution: This function may receive untrusted input.
    438   The data size is external input, so this function will validate it carefully to avoid buffer overflow.
    439 
    440   @param[in]      VariableName       Name of Variable to be found.
    441   @param[in]      VendorGuid         Variable vendor GUID.
    442   @param[out]     Attributes         Attribute value of the variable found.
    443   @param[in, out] DataSize           Size of Data found. If size is less than the
    444                                      data, this value contains the required size.
    445   @param[out]     Data               Data pointer.
    446 
    447   @retval EFI_INVALID_PARAMETER      Invalid parameter.
    448   @retval EFI_SUCCESS                Find the specified variable.
    449   @retval EFI_NOT_FOUND              Not found.
    450   @retval EFI_BUFFER_TO_SMALL        DataSize is too small for the result.
    451 
    452 **/
    453 EFI_STATUS
    454 EFIAPI
    455 RuntimeServiceGetVariable (
    456   IN      CHAR16                            *VariableName,
    457   IN      EFI_GUID                          *VendorGuid,
    458   OUT     UINT32                            *Attributes OPTIONAL,
    459   IN OUT  UINTN                             *DataSize,
    460   OUT     VOID                              *Data
    461   )
    462 {
    463   EFI_STATUS                                Status;
    464   UINTN                                     PayloadSize;
    465   SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE  *SmmVariableHeader;
    466   UINTN                                     TempDataSize;
    467   UINTN                                     VariableNameSize;
    468 
    469   if (VariableName == NULL || VendorGuid == NULL || DataSize == NULL) {
    470     return EFI_INVALID_PARAMETER;
    471   }
    472 
    473   TempDataSize          = *DataSize;
    474   VariableNameSize      = StrSize (VariableName);
    475   SmmVariableHeader     = NULL;
    476 
    477   //
    478   // If VariableName exceeds SMM payload limit. Return failure
    479   //
    480   if (VariableNameSize > mVariableBufferPayloadSize - OFFSET_OF (SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE, Name)) {
    481     return EFI_INVALID_PARAMETER;
    482   }
    483 
    484   AcquireLockOnlyAtBootTime(&mVariableServicesLock);
    485 
    486   //
    487   // Init the communicate buffer. The buffer data size is:
    488   // SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + PayloadSize.
    489   //
    490   if (TempDataSize > mVariableBufferPayloadSize - OFFSET_OF (SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE, Name) - VariableNameSize) {
    491     //
    492     // If output data buffer exceed SMM payload limit. Trim output buffer to SMM payload size
    493     //
    494     TempDataSize = mVariableBufferPayloadSize - OFFSET_OF (SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE, Name) - VariableNameSize;
    495   }
    496   PayloadSize = OFFSET_OF (SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE, Name) + VariableNameSize + TempDataSize;
    497 
    498   Status = InitCommunicateBuffer ((VOID **)&SmmVariableHeader, PayloadSize, SMM_VARIABLE_FUNCTION_GET_VARIABLE);
    499   if (EFI_ERROR (Status)) {
    500     goto Done;
    501   }
    502   ASSERT (SmmVariableHeader != NULL);
    503 
    504   CopyGuid (&SmmVariableHeader->Guid, VendorGuid);
    505   SmmVariableHeader->DataSize   = TempDataSize;
    506   SmmVariableHeader->NameSize   = VariableNameSize;
    507   if (Attributes == NULL) {
    508     SmmVariableHeader->Attributes = 0;
    509   } else {
    510     SmmVariableHeader->Attributes = *Attributes;
    511   }
    512   CopyMem (SmmVariableHeader->Name, VariableName, SmmVariableHeader->NameSize);
    513 
    514   //
    515   // Send data to SMM.
    516   //
    517   Status = SendCommunicateBuffer (PayloadSize);
    518 
    519   //
    520   // Get data from SMM.
    521   //
    522   if (Status == EFI_SUCCESS || Status == EFI_BUFFER_TOO_SMALL) {
    523     //
    524     // SMM CommBuffer DataSize can be a trimed value
    525     // Only update DataSize when needed
    526     //
    527     *DataSize = SmmVariableHeader->DataSize;
    528   }
    529   if (Attributes != NULL) {
    530     *Attributes = SmmVariableHeader->Attributes;
    531   }
    532 
    533   if (EFI_ERROR (Status)) {
    534     goto Done;
    535   }
    536 
    537   if (Data != NULL) {
    538     CopyMem (Data, (UINT8 *)SmmVariableHeader->Name + SmmVariableHeader->NameSize, SmmVariableHeader->DataSize);
    539   } else {
    540     Status = EFI_INVALID_PARAMETER;
    541   }
    542 
    543 Done:
    544   ReleaseLockOnlyAtBootTime (&mVariableServicesLock);
    545   return Status;
    546 }
    547 
    548 
    549 /**
    550   This code Finds the Next available variable.
    551 
    552   @param[in, out] VariableNameSize   Size of the variable name.
    553   @param[in, out] VariableName       Pointer to variable name.
    554   @param[in, out] VendorGuid         Variable Vendor Guid.
    555 
    556   @retval EFI_INVALID_PARAMETER      Invalid parameter.
    557   @retval EFI_SUCCESS                Find the specified variable.
    558   @retval EFI_NOT_FOUND              Not found.
    559   @retval EFI_BUFFER_TO_SMALL        DataSize is too small for the result.
    560 
    561 **/
    562 EFI_STATUS
    563 EFIAPI
    564 RuntimeServiceGetNextVariableName (
    565   IN OUT  UINTN                             *VariableNameSize,
    566   IN OUT  CHAR16                            *VariableName,
    567   IN OUT  EFI_GUID                          *VendorGuid
    568   )
    569 {
    570   EFI_STATUS                                      Status;
    571   UINTN                                           PayloadSize;
    572   SMM_VARIABLE_COMMUNICATE_GET_NEXT_VARIABLE_NAME *SmmGetNextVariableName;
    573   UINTN                                           OutVariableNameSize;
    574   UINTN                                           InVariableNameSize;
    575 
    576   if (VariableNameSize == NULL || VariableName == NULL || VendorGuid == NULL) {
    577     return EFI_INVALID_PARAMETER;
    578   }
    579 
    580   OutVariableNameSize   = *VariableNameSize;
    581   InVariableNameSize    = StrSize (VariableName);
    582   SmmGetNextVariableName = NULL;
    583 
    584   //
    585   // If input string exceeds SMM payload limit. Return failure
    586   //
    587   if (InVariableNameSize > mVariableBufferPayloadSize - OFFSET_OF (SMM_VARIABLE_COMMUNICATE_GET_NEXT_VARIABLE_NAME, Name)) {
    588     return EFI_INVALID_PARAMETER;
    589   }
    590 
    591   AcquireLockOnlyAtBootTime(&mVariableServicesLock);
    592 
    593   //
    594   // Init the communicate buffer. The buffer data size is:
    595   // SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + PayloadSize.
    596   //
    597   if (OutVariableNameSize > mVariableBufferPayloadSize - OFFSET_OF (SMM_VARIABLE_COMMUNICATE_GET_NEXT_VARIABLE_NAME, Name)) {
    598     //
    599     // If output buffer exceed SMM payload limit. Trim output buffer to SMM payload size
    600     //
    601     OutVariableNameSize = mVariableBufferPayloadSize - OFFSET_OF (SMM_VARIABLE_COMMUNICATE_GET_NEXT_VARIABLE_NAME, Name);
    602   }
    603   //
    604   // Payload should be Guid + NameSize + MAX of Input & Output buffer
    605   //
    606   PayloadSize = OFFSET_OF (SMM_VARIABLE_COMMUNICATE_GET_NEXT_VARIABLE_NAME, Name) + MAX (OutVariableNameSize, InVariableNameSize);
    607 
    608   Status = InitCommunicateBuffer ((VOID **)&SmmGetNextVariableName, PayloadSize, SMM_VARIABLE_FUNCTION_GET_NEXT_VARIABLE_NAME);
    609   if (EFI_ERROR (Status)) {
    610     goto Done;
    611   }
    612   ASSERT (SmmGetNextVariableName != NULL);
    613 
    614   //
    615   // SMM comm buffer->NameSize is buffer size for return string
    616   //
    617   SmmGetNextVariableName->NameSize = OutVariableNameSize;
    618 
    619   CopyGuid (&SmmGetNextVariableName->Guid, VendorGuid);
    620   //
    621   // Copy whole string
    622   //
    623   CopyMem (SmmGetNextVariableName->Name, VariableName, InVariableNameSize);
    624   if (OutVariableNameSize > InVariableNameSize) {
    625     ZeroMem ((UINT8 *) SmmGetNextVariableName->Name + InVariableNameSize, OutVariableNameSize - InVariableNameSize);
    626   }
    627 
    628   //
    629   // Send data to SMM
    630   //
    631   Status = SendCommunicateBuffer (PayloadSize);
    632 
    633   //
    634   // Get data from SMM.
    635   //
    636   if (Status == EFI_SUCCESS || Status == EFI_BUFFER_TOO_SMALL) {
    637     //
    638     // SMM CommBuffer NameSize can be a trimed value
    639     // Only update VariableNameSize when needed
    640     //
    641     *VariableNameSize = SmmGetNextVariableName->NameSize;
    642   }
    643   if (EFI_ERROR (Status)) {
    644     goto Done;
    645   }
    646 
    647   CopyGuid (VendorGuid, &SmmGetNextVariableName->Guid);
    648   CopyMem (VariableName, SmmGetNextVariableName->Name, SmmGetNextVariableName->NameSize);
    649 
    650 Done:
    651   ReleaseLockOnlyAtBootTime (&mVariableServicesLock);
    652   return Status;
    653 }
    654 
    655 /**
    656   This code sets variable in storage blocks (Volatile or Non-Volatile).
    657 
    658   Caution: This function may receive untrusted input.
    659   The data size and data are external input, so this function will validate it carefully to avoid buffer overflow.
    660 
    661   @param[in] VariableName                 Name of Variable to be found.
    662   @param[in] VendorGuid                   Variable vendor GUID.
    663   @param[in] Attributes                   Attribute value of the variable found
    664   @param[in] DataSize                     Size of Data found. If size is less than the
    665                                           data, this value contains the required size.
    666   @param[in] Data                         Data pointer.
    667 
    668   @retval EFI_INVALID_PARAMETER           Invalid parameter.
    669   @retval EFI_SUCCESS                     Set successfully.
    670   @retval EFI_OUT_OF_RESOURCES            Resource not enough to set variable.
    671   @retval EFI_NOT_FOUND                   Not found.
    672   @retval EFI_WRITE_PROTECTED             Variable is read-only.
    673 
    674 **/
    675 EFI_STATUS
    676 EFIAPI
    677 RuntimeServiceSetVariable (
    678   IN CHAR16                                 *VariableName,
    679   IN EFI_GUID                               *VendorGuid,
    680   IN UINT32                                 Attributes,
    681   IN UINTN                                  DataSize,
    682   IN VOID                                   *Data
    683   )
    684 {
    685   EFI_STATUS                                Status;
    686   UINTN                                     PayloadSize;
    687   SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE  *SmmVariableHeader;
    688   UINTN                                     VariableNameSize;
    689 
    690   //
    691   // Check input parameters.
    692   //
    693   if (VariableName == NULL || VariableName[0] == 0 || VendorGuid == NULL) {
    694     return EFI_INVALID_PARAMETER;
    695   }
    696 
    697   if (DataSize != 0 && Data == NULL) {
    698     return EFI_INVALID_PARAMETER;
    699   }
    700 
    701   VariableNameSize      = StrSize (VariableName);
    702   SmmVariableHeader     = NULL;
    703 
    704   //
    705   // If VariableName or DataSize exceeds SMM payload limit. Return failure
    706   //
    707   if ((VariableNameSize > mVariableBufferPayloadSize - OFFSET_OF (SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE, Name)) ||
    708       (DataSize > mVariableBufferPayloadSize - OFFSET_OF (SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE, Name) - VariableNameSize)){
    709     return EFI_INVALID_PARAMETER;
    710   }
    711 
    712   AcquireLockOnlyAtBootTime(&mVariableServicesLock);
    713 
    714   //
    715   // Init the communicate buffer. The buffer data size is:
    716   // SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + PayloadSize.
    717   //
    718   PayloadSize = OFFSET_OF (SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE, Name) + VariableNameSize + DataSize;
    719   Status = InitCommunicateBuffer ((VOID **)&SmmVariableHeader, PayloadSize, SMM_VARIABLE_FUNCTION_SET_VARIABLE);
    720   if (EFI_ERROR (Status)) {
    721     goto Done;
    722   }
    723   ASSERT (SmmVariableHeader != NULL);
    724 
    725   CopyGuid ((EFI_GUID *) &SmmVariableHeader->Guid, VendorGuid);
    726   SmmVariableHeader->DataSize   = DataSize;
    727   SmmVariableHeader->NameSize   = VariableNameSize;
    728   SmmVariableHeader->Attributes = Attributes;
    729   CopyMem (SmmVariableHeader->Name, VariableName, SmmVariableHeader->NameSize);
    730   CopyMem ((UINT8 *) SmmVariableHeader->Name + SmmVariableHeader->NameSize, Data, DataSize);
    731 
    732   //
    733   // Send data to SMM.
    734   //
    735   Status = SendCommunicateBuffer (PayloadSize);
    736 
    737 Done:
    738   ReleaseLockOnlyAtBootTime (&mVariableServicesLock);
    739 
    740   if (!EfiAtRuntime ()) {
    741     if (!EFI_ERROR (Status)) {
    742       SecureBootHook (
    743         VariableName,
    744         VendorGuid
    745         );
    746     }
    747   }
    748   return Status;
    749 }
    750 
    751 
    752 /**
    753   This code returns information about the EFI variables.
    754 
    755   @param[in]  Attributes                   Attributes bitmask to specify the type of variables
    756                                            on which to return information.
    757   @param[out] MaximumVariableStorageSize   Pointer to the maximum size of the storage space available
    758                                            for the EFI variables associated with the attributes specified.
    759   @param[out] RemainingVariableStorageSize Pointer to the remaining size of the storage space available
    760                                            for EFI variables associated with the attributes specified.
    761   @param[out] MaximumVariableSize          Pointer to the maximum size of an individual EFI variables
    762                                            associated with the attributes specified.
    763 
    764   @retval EFI_INVALID_PARAMETER            An invalid combination of attribute bits was supplied.
    765   @retval EFI_SUCCESS                      Query successfully.
    766   @retval EFI_UNSUPPORTED                  The attribute is not supported on this platform.
    767 
    768 **/
    769 EFI_STATUS
    770 EFIAPI
    771 RuntimeServiceQueryVariableInfo (
    772   IN  UINT32                                Attributes,
    773   OUT UINT64                                *MaximumVariableStorageSize,
    774   OUT UINT64                                *RemainingVariableStorageSize,
    775   OUT UINT64                                *MaximumVariableSize
    776   )
    777 {
    778   EFI_STATUS                                Status;
    779   UINTN                                     PayloadSize;
    780   SMM_VARIABLE_COMMUNICATE_QUERY_VARIABLE_INFO *SmmQueryVariableInfo;
    781 
    782   SmmQueryVariableInfo = NULL;
    783 
    784   if(MaximumVariableStorageSize == NULL || RemainingVariableStorageSize == NULL || MaximumVariableSize == NULL || Attributes == 0) {
    785     return EFI_INVALID_PARAMETER;
    786   }
    787 
    788   AcquireLockOnlyAtBootTime(&mVariableServicesLock);
    789 
    790   //
    791   // Init the communicate buffer. The buffer data size is:
    792   // SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + PayloadSize;
    793   //
    794   PayloadSize = sizeof (SMM_VARIABLE_COMMUNICATE_QUERY_VARIABLE_INFO);
    795   Status = InitCommunicateBuffer ((VOID **)&SmmQueryVariableInfo, PayloadSize, SMM_VARIABLE_FUNCTION_QUERY_VARIABLE_INFO);
    796   if (EFI_ERROR (Status)) {
    797     goto Done;
    798   }
    799   ASSERT (SmmQueryVariableInfo != NULL);
    800 
    801   SmmQueryVariableInfo->Attributes  = Attributes;
    802 
    803   //
    804   // Send data to SMM.
    805   //
    806   Status = SendCommunicateBuffer (PayloadSize);
    807   if (EFI_ERROR (Status)) {
    808     goto Done;
    809   }
    810 
    811   //
    812   // Get data from SMM.
    813   //
    814   *MaximumVariableSize          = SmmQueryVariableInfo->MaximumVariableSize;
    815   *MaximumVariableStorageSize   = SmmQueryVariableInfo->MaximumVariableStorageSize;
    816   *RemainingVariableStorageSize = SmmQueryVariableInfo->RemainingVariableStorageSize;
    817 
    818 Done:
    819   ReleaseLockOnlyAtBootTime (&mVariableServicesLock);
    820   return Status;
    821 }
    822 
    823 
    824 /**
    825   Exit Boot Services Event notification handler.
    826 
    827   Notify SMM variable driver about the event.
    828 
    829   @param[in]  Event     Event whose notification function is being invoked.
    830   @param[in]  Context   Pointer to the notification function's context.
    831 
    832 **/
    833 VOID
    834 EFIAPI
    835 OnExitBootServices (
    836   IN      EFI_EVENT                         Event,
    837   IN      VOID                              *Context
    838   )
    839 {
    840   //
    841   // Init the communicate buffer. The buffer data size is:
    842   // SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE.
    843   //
    844   InitCommunicateBuffer (NULL, 0, SMM_VARIABLE_FUNCTION_EXIT_BOOT_SERVICE);
    845 
    846   //
    847   // Send data to SMM.
    848   //
    849   SendCommunicateBuffer (0);
    850 }
    851 
    852 
    853 /**
    854   On Ready To Boot Services Event notification handler.
    855 
    856   Notify SMM variable driver about the event.
    857 
    858   @param[in]  Event     Event whose notification function is being invoked
    859   @param[in]  Context   Pointer to the notification function's context
    860 
    861 **/
    862 VOID
    863 EFIAPI
    864 OnReadyToBoot (
    865   IN      EFI_EVENT                         Event,
    866   IN      VOID                              *Context
    867   )
    868 {
    869   //
    870   // Init the communicate buffer. The buffer data size is:
    871   // SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE.
    872   //
    873   InitCommunicateBuffer (NULL, 0, SMM_VARIABLE_FUNCTION_READY_TO_BOOT);
    874 
    875   //
    876   // Send data to SMM.
    877   //
    878   SendCommunicateBuffer (0);
    879 
    880   gBS->CloseEvent (Event);
    881 }
    882 
    883 
    884 /**
    885   Notification function of EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE.
    886 
    887   This is a notification function registered on EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE event.
    888   It convers pointer to new virtual address.
    889 
    890   @param[in]  Event        Event whose notification function is being invoked.
    891   @param[in]  Context      Pointer to the notification function's context.
    892 
    893 **/
    894 VOID
    895 EFIAPI
    896 VariableAddressChangeEvent (
    897   IN EFI_EVENT                              Event,
    898   IN VOID                                   *Context
    899   )
    900 {
    901   EfiConvertPointer (0x0, (VOID **) &mVariableBuffer);
    902   EfiConvertPointer (0x0, (VOID **) &mSmmCommunication);
    903 }
    904 
    905 /**
    906   This code gets variable payload size.
    907 
    908   @param[out] VariablePayloadSize   Output pointer to variable payload size.
    909 
    910   @retval EFI_SUCCESS               Get successfully.
    911   @retval Others                    Get unsuccessfully.
    912 
    913 **/
    914 EFI_STATUS
    915 EFIAPI
    916 GetVariablePayloadSize (
    917   OUT UINTN                         *VariablePayloadSize
    918   )
    919 {
    920   EFI_STATUS                                Status;
    921   SMM_VARIABLE_COMMUNICATE_GET_PAYLOAD_SIZE *SmmGetPayloadSize;
    922   EFI_SMM_COMMUNICATE_HEADER                *SmmCommunicateHeader;
    923   SMM_VARIABLE_COMMUNICATE_HEADER           *SmmVariableFunctionHeader;
    924   UINTN                                     CommSize;
    925   UINT8                                     *CommBuffer;
    926 
    927   SmmGetPayloadSize = NULL;
    928   CommBuffer = NULL;
    929 
    930   if(VariablePayloadSize == NULL) {
    931     return EFI_INVALID_PARAMETER;
    932   }
    933 
    934   AcquireLockOnlyAtBootTime(&mVariableServicesLock);
    935 
    936   //
    937   // Init the communicate buffer. The buffer data size is:
    938   // SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + sizeof (SMM_VARIABLE_COMMUNICATE_GET_PAYLOAD_SIZE);
    939   //
    940   CommSize = SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + sizeof (SMM_VARIABLE_COMMUNICATE_GET_PAYLOAD_SIZE);
    941   CommBuffer = AllocateZeroPool (CommSize);
    942   if (CommBuffer == NULL) {
    943     Status = EFI_OUT_OF_RESOURCES;
    944     goto Done;
    945   }
    946 
    947   SmmCommunicateHeader = (EFI_SMM_COMMUNICATE_HEADER *) CommBuffer;
    948   CopyGuid (&SmmCommunicateHeader->HeaderGuid, &gEfiSmmVariableProtocolGuid);
    949   SmmCommunicateHeader->MessageLength = SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + sizeof (SMM_VARIABLE_COMMUNICATE_GET_PAYLOAD_SIZE);
    950 
    951   SmmVariableFunctionHeader = (SMM_VARIABLE_COMMUNICATE_HEADER *) SmmCommunicateHeader->Data;
    952   SmmVariableFunctionHeader->Function = SMM_VARIABLE_FUNCTION_GET_PAYLOAD_SIZE;
    953   SmmGetPayloadSize = (SMM_VARIABLE_COMMUNICATE_GET_PAYLOAD_SIZE *) SmmVariableFunctionHeader->Data;
    954 
    955   //
    956   // Send data to SMM.
    957   //
    958   Status = mSmmCommunication->Communicate (mSmmCommunication, CommBuffer, &CommSize);
    959   ASSERT_EFI_ERROR (Status);
    960 
    961   Status = SmmVariableFunctionHeader->ReturnStatus;
    962   if (EFI_ERROR (Status)) {
    963     goto Done;
    964   }
    965 
    966   //
    967   // Get data from SMM.
    968   //
    969   *VariablePayloadSize = SmmGetPayloadSize->VariablePayloadSize;
    970 
    971 Done:
    972   if (CommBuffer != NULL) {
    973     FreePool (CommBuffer);
    974   }
    975   ReleaseLockOnlyAtBootTime (&mVariableServicesLock);
    976   return Status;
    977 }
    978 
    979 /**
    980   Initialize variable service and install Variable Architectural protocol.
    981 
    982   @param[in] Event    Event whose notification function is being invoked.
    983   @param[in] Context  Pointer to the notification function's context.
    984 
    985 **/
    986 VOID
    987 EFIAPI
    988 SmmVariableReady (
    989   IN  EFI_EVENT                             Event,
    990   IN  VOID                                  *Context
    991   )
    992 {
    993   EFI_STATUS                                Status;
    994 
    995   Status = gBS->LocateProtocol (&gEfiSmmVariableProtocolGuid, NULL, (VOID **)&mSmmVariable);
    996   if (EFI_ERROR (Status)) {
    997     return;
    998   }
    999 
   1000   Status = gBS->LocateProtocol (&gEfiSmmCommunicationProtocolGuid, NULL, (VOID **) &mSmmCommunication);
   1001   ASSERT_EFI_ERROR (Status);
   1002 
   1003   //
   1004   // Allocate memory for variable communicate buffer.
   1005   //
   1006   Status = GetVariablePayloadSize (&mVariableBufferPayloadSize);
   1007   ASSERT_EFI_ERROR (Status);
   1008   mVariableBufferSize  = SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + mVariableBufferPayloadSize;
   1009   mVariableBuffer      = AllocateRuntimePool (mVariableBufferSize);
   1010   ASSERT (mVariableBuffer != NULL);
   1011 
   1012   //
   1013   // Save the buffer physical address used for SMM conmunication.
   1014   //
   1015   mVariableBufferPhysical = mVariableBuffer;
   1016 
   1017   gRT->GetVariable         = RuntimeServiceGetVariable;
   1018   gRT->GetNextVariableName = RuntimeServiceGetNextVariableName;
   1019   gRT->SetVariable         = RuntimeServiceSetVariable;
   1020   gRT->QueryVariableInfo   = RuntimeServiceQueryVariableInfo;
   1021 
   1022   //
   1023   // Install the Variable Architectural Protocol on a new handle.
   1024   //
   1025   Status = gBS->InstallProtocolInterface (
   1026                   &mHandle,
   1027                   &gEfiVariableArchProtocolGuid,
   1028                   EFI_NATIVE_INTERFACE,
   1029                   NULL
   1030                   );
   1031   ASSERT_EFI_ERROR (Status);
   1032 
   1033   mVariableLock.RequestToLock = VariableLockRequestToLock;
   1034   Status = gBS->InstallMultipleProtocolInterfaces (
   1035                   &mHandle,
   1036                   &gEdkiiVariableLockProtocolGuid,
   1037                   &mVariableLock,
   1038                   NULL
   1039                   );
   1040   ASSERT_EFI_ERROR (Status);
   1041 
   1042   mVarCheck.RegisterSetVariableCheckHandler = VarCheckRegisterSetVariableCheckHandler;
   1043   mVarCheck.VariablePropertySet = VarCheckVariablePropertySet;
   1044   mVarCheck.VariablePropertyGet = VarCheckVariablePropertyGet;
   1045   Status = gBS->InstallMultipleProtocolInterfaces (
   1046                   &mHandle,
   1047                   &gEdkiiVarCheckProtocolGuid,
   1048                   &mVarCheck,
   1049                   NULL
   1050                   );
   1051   ASSERT_EFI_ERROR (Status);
   1052 
   1053   gBS->CloseEvent (Event);
   1054 }
   1055 
   1056 
   1057 /**
   1058   SMM Non-Volatile variable write service is ready notify event handler.
   1059 
   1060   @param[in] Event    Event whose notification function is being invoked.
   1061   @param[in] Context  Pointer to the notification function's context.
   1062 
   1063 **/
   1064 VOID
   1065 EFIAPI
   1066 SmmVariableWriteReady (
   1067   IN  EFI_EVENT                             Event,
   1068   IN  VOID                                  *Context
   1069   )
   1070 {
   1071   EFI_STATUS                                Status;
   1072   VOID                                      *ProtocolOps;
   1073 
   1074   //
   1075   // Check whether the protocol is installed or not.
   1076   //
   1077   Status = gBS->LocateProtocol (&gSmmVariableWriteGuid, NULL, (VOID **) &ProtocolOps);
   1078   if (EFI_ERROR (Status)) {
   1079     return;
   1080   }
   1081 
   1082   Status = gBS->InstallProtocolInterface (
   1083                   &mHandle,
   1084                   &gEfiVariableWriteArchProtocolGuid,
   1085                   EFI_NATIVE_INTERFACE,
   1086                   NULL
   1087                   );
   1088   ASSERT_EFI_ERROR (Status);
   1089 
   1090   gBS->CloseEvent (Event);
   1091 }
   1092 
   1093 
   1094 /**
   1095   Variable Driver main entry point. The Variable driver places the 4 EFI
   1096   runtime services in the EFI System Table and installs arch protocols
   1097   for variable read and write services being available. It also registers
   1098   a notification function for an EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE event.
   1099 
   1100   @param[in] ImageHandle    The firmware allocated handle for the EFI image.
   1101   @param[in] SystemTable    A pointer to the EFI System Table.
   1102 
   1103   @retval EFI_SUCCESS       Variable service successfully initialized.
   1104 
   1105 **/
   1106 EFI_STATUS
   1107 EFIAPI
   1108 VariableSmmRuntimeInitialize (
   1109   IN EFI_HANDLE                             ImageHandle,
   1110   IN EFI_SYSTEM_TABLE                       *SystemTable
   1111   )
   1112 {
   1113   VOID                                      *SmmVariableRegistration;
   1114   VOID                                      *SmmVariableWriteRegistration;
   1115   EFI_EVENT                                 OnReadyToBootEvent;
   1116   EFI_EVENT                                 ExitBootServiceEvent;
   1117   EFI_EVENT                                 LegacyBootEvent;
   1118 
   1119   EfiInitializeLock (&mVariableServicesLock, TPL_NOTIFY);
   1120 
   1121   //
   1122   // Smm variable service is ready
   1123   //
   1124   EfiCreateProtocolNotifyEvent (
   1125     &gEfiSmmVariableProtocolGuid,
   1126     TPL_CALLBACK,
   1127     SmmVariableReady,
   1128     NULL,
   1129     &SmmVariableRegistration
   1130     );
   1131 
   1132   //
   1133   // Smm Non-Volatile variable write service is ready
   1134   //
   1135   EfiCreateProtocolNotifyEvent (
   1136     &gSmmVariableWriteGuid,
   1137     TPL_CALLBACK,
   1138     SmmVariableWriteReady,
   1139     NULL,
   1140     &SmmVariableWriteRegistration
   1141     );
   1142 
   1143   //
   1144   // Register the event to reclaim variable for OS usage.
   1145   //
   1146   EfiCreateEventReadyToBootEx (
   1147     TPL_NOTIFY,
   1148     OnReadyToBoot,
   1149     NULL,
   1150     &OnReadyToBootEvent
   1151     );
   1152 
   1153   //
   1154   // Register the event to inform SMM variable that it is at runtime.
   1155   //
   1156   gBS->CreateEventEx (
   1157          EVT_NOTIFY_SIGNAL,
   1158          TPL_NOTIFY,
   1159          OnExitBootServices,
   1160          NULL,
   1161          &gEfiEventExitBootServicesGuid,
   1162          &ExitBootServiceEvent
   1163          );
   1164 
   1165   //
   1166   // Register the event to inform SMM variable that it is at runtime for legacy boot.
   1167   // Reuse OnExitBootServices() here.
   1168   //
   1169   EfiCreateEventLegacyBootEx(
   1170     TPL_NOTIFY,
   1171     OnExitBootServices,
   1172     NULL,
   1173     &LegacyBootEvent
   1174     );
   1175 
   1176   //
   1177   // Register the event to convert the pointer for runtime.
   1178   //
   1179   gBS->CreateEventEx (
   1180          EVT_NOTIFY_SIGNAL,
   1181          TPL_NOTIFY,
   1182          VariableAddressChangeEvent,
   1183          NULL,
   1184          &gEfiEventVirtualAddressChangeGuid,
   1185          &mVirtualAddressChangeEvent
   1186          );
   1187 
   1188   return EFI_SUCCESS;
   1189 }
   1190 
   1191