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 
      5 Copyright (C) 2013, Red Hat, Inc.
      6 Copyright (c) 2006 - 2015, Intel Corporation. All rights reserved.<BR>
      7 (C) Copyright 2015 Hewlett Packard Enterprise Development LP<BR>
      8 This program and the accompanying materials
      9 are licensed and made available under the terms and conditions of the BSD License
     10 which accompanies this distribution.  The full text of the license may be found at
     11 http://opensource.org/licenses/bsd-license.php
     12 
     13 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
     14 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
     15 
     16 **/
     17 
     18 #include "Variable.h"
     19 
     20 extern VARIABLE_STORE_HEADER        *mNvVariableCache;
     21 extern EFI_FIRMWARE_VOLUME_HEADER   *mNvFvHeaderCache;
     22 extern VARIABLE_INFO_ENTRY          *gVariableInfo;
     23 EFI_HANDLE                          mHandle                    = NULL;
     24 EFI_EVENT                           mVirtualAddressChangeEvent = NULL;
     25 EFI_EVENT                           mFtwRegistration           = NULL;
     26 extern BOOLEAN                      mEndOfDxe;
     27 VOID                                ***mVarCheckAddressPointer = NULL;
     28 UINTN                               mVarCheckAddressPointerCount = 0;
     29 EDKII_VARIABLE_LOCK_PROTOCOL        mVariableLock              = { VariableLockRequestToLock };
     30 EDKII_VAR_CHECK_PROTOCOL            mVarCheck                  = { VarCheckRegisterSetVariableCheckHandler,
     31                                                                     VarCheckVariablePropertySet,
     32                                                                     VarCheckVariablePropertyGet };
     33 
     34 /**
     35   Return TRUE if ExitBootServices () has been called.
     36 
     37   @retval TRUE If ExitBootServices () has been called.
     38 **/
     39 BOOLEAN
     40 AtRuntime (
     41   VOID
     42   )
     43 {
     44   return EfiAtRuntime ();
     45 }
     46 
     47 
     48 /**
     49   Initializes a basic mutual exclusion lock.
     50 
     51   This function initializes a basic mutual exclusion lock to the released state
     52   and returns the lock.  Each lock provides mutual exclusion access at its task
     53   priority level.  Since there is no preemption or multiprocessor support in EFI,
     54   acquiring the lock only consists of raising to the locks TPL.
     55   If Lock is NULL, then ASSERT().
     56   If Priority is not a valid TPL value, then ASSERT().
     57 
     58   @param  Lock       A pointer to the lock data structure to initialize.
     59   @param  Priority   EFI TPL is associated with the lock.
     60 
     61   @return The lock.
     62 
     63 **/
     64 EFI_LOCK *
     65 InitializeLock (
     66   IN OUT EFI_LOCK                         *Lock,
     67   IN     EFI_TPL                          Priority
     68   )
     69 {
     70   return EfiInitializeLock (Lock, Priority);
     71 }
     72 
     73 
     74 /**
     75   Acquires lock only at boot time. Simply returns at runtime.
     76 
     77   This is a temperary function that will be removed when
     78   EfiAcquireLock() in UefiLib can handle the call in UEFI
     79   Runtimer driver in RT phase.
     80   It calls EfiAcquireLock() at boot time, and simply returns
     81   at runtime.
     82 
     83   @param  Lock         A pointer to the lock to acquire.
     84 
     85 **/
     86 VOID
     87 AcquireLockOnlyAtBootTime (
     88   IN EFI_LOCK                             *Lock
     89   )
     90 {
     91   if (!AtRuntime ()) {
     92     EfiAcquireLock (Lock);
     93   }
     94 }
     95 
     96 
     97 /**
     98   Releases lock only at boot time. Simply returns at runtime.
     99 
    100   This is a temperary function which will be removed when
    101   EfiReleaseLock() in UefiLib can handle the call in UEFI
    102   Runtimer driver in RT phase.
    103   It calls EfiReleaseLock() at boot time and simply returns
    104   at runtime.
    105 
    106   @param  Lock         A pointer to the lock to release.
    107 
    108 **/
    109 VOID
    110 ReleaseLockOnlyAtBootTime (
    111   IN EFI_LOCK                             *Lock
    112   )
    113 {
    114   if (!AtRuntime ()) {
    115     EfiReleaseLock (Lock);
    116   }
    117 }
    118 
    119 /**
    120   Retrive the Fault Tolerent Write protocol interface.
    121 
    122   @param[out] FtwProtocol       The interface of Ftw protocol
    123 
    124   @retval EFI_SUCCESS           The FTW protocol instance was found and returned in FtwProtocol.
    125   @retval EFI_NOT_FOUND         The FTW protocol instance was not found.
    126   @retval EFI_INVALID_PARAMETER SarProtocol is NULL.
    127 
    128 **/
    129 EFI_STATUS
    130 GetFtwProtocol (
    131   OUT VOID                                **FtwProtocol
    132   )
    133 {
    134   EFI_STATUS                              Status;
    135 
    136   //
    137   // Locate Fault Tolerent Write protocol
    138   //
    139   Status = gBS->LocateProtocol (
    140                   &gEfiFaultTolerantWriteProtocolGuid,
    141                   NULL,
    142                   FtwProtocol
    143                   );
    144   return Status;
    145 }
    146 
    147 /**
    148   Retrive the FVB protocol interface by HANDLE.
    149 
    150   @param[in]  FvBlockHandle     The handle of FVB protocol that provides services for
    151                                 reading, writing, and erasing the target block.
    152   @param[out] FvBlock           The interface of FVB protocol
    153 
    154   @retval EFI_SUCCESS           The interface information for the specified protocol was returned.
    155   @retval EFI_UNSUPPORTED       The device does not support the FVB protocol.
    156   @retval EFI_INVALID_PARAMETER FvBlockHandle is not a valid EFI_HANDLE or FvBlock is NULL.
    157 
    158 **/
    159 EFI_STATUS
    160 GetFvbByHandle (
    161   IN  EFI_HANDLE                          FvBlockHandle,
    162   OUT EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL  **FvBlock
    163   )
    164 {
    165   //
    166   // To get the FVB protocol interface on the handle
    167   //
    168   return gBS->HandleProtocol (
    169                 FvBlockHandle,
    170                 &gEfiFirmwareVolumeBlockProtocolGuid,
    171                 (VOID **) FvBlock
    172                 );
    173 }
    174 
    175 
    176 /**
    177   Function returns an array of handles that support the FVB protocol
    178   in a buffer allocated from pool.
    179 
    180   @param[out]  NumberHandles    The number of handles returned in Buffer.
    181   @param[out]  Buffer           A pointer to the buffer to return the requested
    182                                 array of  handles that support FVB protocol.
    183 
    184   @retval EFI_SUCCESS           The array of handles was returned in Buffer, and the number of
    185                                 handles in Buffer was returned in NumberHandles.
    186   @retval EFI_NOT_FOUND         No FVB handle was found.
    187   @retval EFI_OUT_OF_RESOURCES  There is not enough pool memory to store the matching results.
    188   @retval EFI_INVALID_PARAMETER NumberHandles is NULL or Buffer is NULL.
    189 
    190 **/
    191 EFI_STATUS
    192 GetFvbCountAndBuffer (
    193   OUT UINTN                               *NumberHandles,
    194   OUT EFI_HANDLE                          **Buffer
    195   )
    196 {
    197   EFI_STATUS                              Status;
    198 
    199   //
    200   // Locate all handles of Fvb protocol
    201   //
    202   Status = gBS->LocateHandleBuffer (
    203                   ByProtocol,
    204                   &gEfiFirmwareVolumeBlockProtocolGuid,
    205                   NULL,
    206                   NumberHandles,
    207                   Buffer
    208                   );
    209   return Status;
    210 }
    211 
    212 
    213 /**
    214   Notification function of EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE.
    215 
    216   This is a notification function registered on EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE event.
    217   It convers pointer to new virtual address.
    218 
    219   @param  Event        Event whose notification function is being invoked.
    220   @param  Context      Pointer to the notification function's context.
    221 
    222 **/
    223 VOID
    224 EFIAPI
    225 VariableClassAddressChangeEvent (
    226   IN EFI_EVENT                            Event,
    227   IN VOID                                 *Context
    228   )
    229 {
    230   UINTN          Index;
    231 
    232   EfiConvertPointer (0x0, (VOID **) &mVariableModuleGlobal->FvbInstance->GetBlockSize);
    233   EfiConvertPointer (0x0, (VOID **) &mVariableModuleGlobal->FvbInstance->GetPhysicalAddress);
    234   EfiConvertPointer (0x0, (VOID **) &mVariableModuleGlobal->FvbInstance->GetAttributes);
    235   EfiConvertPointer (0x0, (VOID **) &mVariableModuleGlobal->FvbInstance->SetAttributes);
    236   EfiConvertPointer (0x0, (VOID **) &mVariableModuleGlobal->FvbInstance->Read);
    237   EfiConvertPointer (0x0, (VOID **) &mVariableModuleGlobal->FvbInstance->Write);
    238   EfiConvertPointer (0x0, (VOID **) &mVariableModuleGlobal->FvbInstance->EraseBlocks);
    239   EfiConvertPointer (0x0, (VOID **) &mVariableModuleGlobal->FvbInstance);
    240   EfiConvertPointer (0x0, (VOID **) &mVariableModuleGlobal->PlatformLangCodes);
    241   EfiConvertPointer (0x0, (VOID **) &mVariableModuleGlobal->LangCodes);
    242   EfiConvertPointer (0x0, (VOID **) &mVariableModuleGlobal->PlatformLang);
    243   EfiConvertPointer (0x0, (VOID **) &mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase);
    244   EfiConvertPointer (0x0, (VOID **) &mVariableModuleGlobal->VariableGlobal.VolatileVariableBase);
    245   EfiConvertPointer (0x0, (VOID **) &mVariableModuleGlobal->VariableGlobal.HobVariableBase);
    246   EfiConvertPointer (0x0, (VOID **) &mVariableModuleGlobal);
    247   EfiConvertPointer (0x0, (VOID **) &mNvVariableCache);
    248   EfiConvertPointer (0x0, (VOID **) &mNvFvHeaderCache);
    249 
    250   if (mAuthContextOut.AddressPointer != NULL) {
    251     for (Index = 0; Index < mAuthContextOut.AddressPointerCount; Index++) {
    252       EfiConvertPointer (0x0, (VOID **) mAuthContextOut.AddressPointer[Index]);
    253     }
    254   }
    255 
    256   if (mVarCheckAddressPointer != NULL) {
    257     for (Index = 0; Index < mVarCheckAddressPointerCount; Index++) {
    258       EfiConvertPointer (0x0, (VOID **) mVarCheckAddressPointer[Index]);
    259     }
    260   }
    261 }
    262 
    263 
    264 /**
    265   Notification function of EVT_GROUP_READY_TO_BOOT event group.
    266 
    267   This is a notification function registered on EVT_GROUP_READY_TO_BOOT event group.
    268   When the Boot Manager is about to load and execute a boot option, it reclaims variable
    269   storage if free size is below the threshold.
    270 
    271   @param  Event        Event whose notification function is being invoked.
    272   @param  Context      Pointer to the notification function's context.
    273 
    274 **/
    275 VOID
    276 EFIAPI
    277 OnReadyToBoot (
    278   EFI_EVENT                               Event,
    279   VOID                                    *Context
    280   )
    281 {
    282   if (!mEndOfDxe) {
    283     //
    284     // Set the End Of DXE bit in case the EFI_END_OF_DXE_EVENT_GROUP_GUID event is not signaled.
    285     //
    286     mEndOfDxe = TRUE;
    287     mVarCheckAddressPointer = VarCheckLibInitializeAtEndOfDxe (&mVarCheckAddressPointerCount);
    288     //
    289     // The initialization for variable quota.
    290     //
    291     InitializeVariableQuota ();
    292   }
    293   ReclaimForOS ();
    294   if (FeaturePcdGet (PcdVariableCollectStatistics)) {
    295     if (mVariableModuleGlobal->VariableGlobal.AuthFormat) {
    296       gBS->InstallConfigurationTable (&gEfiAuthenticatedVariableGuid, gVariableInfo);
    297     } else {
    298       gBS->InstallConfigurationTable (&gEfiVariableGuid, gVariableInfo);
    299     }
    300   }
    301 
    302   gBS->CloseEvent (Event);
    303 }
    304 
    305 /**
    306   Notification function of EFI_END_OF_DXE_EVENT_GROUP_GUID event group.
    307 
    308   This is a notification function registered on EFI_END_OF_DXE_EVENT_GROUP_GUID event group.
    309 
    310   @param  Event        Event whose notification function is being invoked.
    311   @param  Context      Pointer to the notification function's context.
    312 
    313 **/
    314 VOID
    315 EFIAPI
    316 OnEndOfDxe (
    317   EFI_EVENT                               Event,
    318   VOID                                    *Context
    319   )
    320 {
    321   DEBUG ((EFI_D_INFO, "[Variable]END_OF_DXE is signaled\n"));
    322   mEndOfDxe = TRUE;
    323   mVarCheckAddressPointer = VarCheckLibInitializeAtEndOfDxe (&mVarCheckAddressPointerCount);
    324   //
    325   // The initialization for variable quota.
    326   //
    327   InitializeVariableQuota ();
    328   if (PcdGetBool (PcdReclaimVariableSpaceAtEndOfDxe)) {
    329     ReclaimForOS ();
    330   }
    331 
    332   gBS->CloseEvent (Event);
    333 }
    334 
    335 /**
    336   Fault Tolerant Write protocol notification event handler.
    337 
    338   Non-Volatile variable write may needs FTW protocol to reclaim when
    339   writting variable.
    340 
    341   @param[in] Event    Event whose notification function is being invoked.
    342   @param[in] Context  Pointer to the notification function's context.
    343 
    344 **/
    345 VOID
    346 EFIAPI
    347 FtwNotificationEvent (
    348   IN  EFI_EVENT                           Event,
    349   IN  VOID                                *Context
    350   )
    351 {
    352   EFI_STATUS                              Status;
    353   EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL      *FvbProtocol;
    354   EFI_FAULT_TOLERANT_WRITE_PROTOCOL       *FtwProtocol;
    355   EFI_PHYSICAL_ADDRESS                    NvStorageVariableBase;
    356   EFI_GCD_MEMORY_SPACE_DESCRIPTOR         GcdDescriptor;
    357   EFI_PHYSICAL_ADDRESS                    BaseAddress;
    358   UINT64                                  Length;
    359   EFI_PHYSICAL_ADDRESS                    VariableStoreBase;
    360   UINT64                                  VariableStoreLength;
    361   UINTN                                   FtwMaxBlockSize;
    362 
    363   //
    364   // Ensure FTW protocol is installed.
    365   //
    366   Status = GetFtwProtocol ((VOID**) &FtwProtocol);
    367   if (EFI_ERROR (Status)) {
    368     return ;
    369   }
    370 
    371   Status = FtwProtocol->GetMaxBlockSize (FtwProtocol, &FtwMaxBlockSize);
    372   if (!EFI_ERROR (Status)) {
    373     ASSERT (PcdGet32 (PcdFlashNvStorageVariableSize) <= FtwMaxBlockSize);
    374   }
    375 
    376   //
    377   // Find the proper FVB protocol for variable.
    378   //
    379   NvStorageVariableBase = (EFI_PHYSICAL_ADDRESS) PcdGet64 (PcdFlashNvStorageVariableBase64);
    380   if (NvStorageVariableBase == 0) {
    381     NvStorageVariableBase = (EFI_PHYSICAL_ADDRESS) PcdGet32 (PcdFlashNvStorageVariableBase);
    382   }
    383   Status = GetFvbInfoByAddress (NvStorageVariableBase, NULL, &FvbProtocol);
    384   if (EFI_ERROR (Status)) {
    385     return ;
    386   }
    387   mVariableModuleGlobal->FvbInstance = FvbProtocol;
    388 
    389   //
    390   // Mark the variable storage region of the FLASH as RUNTIME.
    391   //
    392   VariableStoreBase   = NvStorageVariableBase + (((EFI_FIRMWARE_VOLUME_HEADER *)(UINTN)(NvStorageVariableBase))->HeaderLength);
    393   VariableStoreLength = ((VARIABLE_STORE_HEADER *)(UINTN)VariableStoreBase)->Size;
    394   BaseAddress = VariableStoreBase & (~EFI_PAGE_MASK);
    395   Length      = VariableStoreLength + (VariableStoreBase - BaseAddress);
    396   Length      = (Length + EFI_PAGE_SIZE - 1) & (~EFI_PAGE_MASK);
    397 
    398   Status      = gDS->GetMemorySpaceDescriptor (BaseAddress, &GcdDescriptor);
    399   if (EFI_ERROR (Status)) {
    400     DEBUG ((DEBUG_WARN, "Variable driver failed to get flash memory attribute.\n"));
    401   } else {
    402     Status = gDS->SetMemorySpaceAttributes (
    403                     BaseAddress,
    404                     Length,
    405                     GcdDescriptor.Attributes | EFI_MEMORY_RUNTIME
    406                     );
    407     if (EFI_ERROR (Status)) {
    408       DEBUG ((DEBUG_WARN, "Variable driver failed to add EFI_MEMORY_RUNTIME attribute to Flash.\n"));
    409     }
    410   }
    411 
    412   Status = VariableWriteServiceInitialize ();
    413   if (EFI_ERROR (Status)) {
    414     DEBUG ((DEBUG_ERROR, "Variable write service initialization failed. Status = %r\n", Status));
    415   }
    416 
    417   //
    418   // Install the Variable Write Architectural protocol.
    419   //
    420   Status = gBS->InstallProtocolInterface (
    421                   &mHandle,
    422                   &gEfiVariableWriteArchProtocolGuid,
    423                   EFI_NATIVE_INTERFACE,
    424                   NULL
    425                   );
    426   ASSERT_EFI_ERROR (Status);
    427 
    428   //
    429   // Close the notify event to avoid install gEfiVariableWriteArchProtocolGuid again.
    430   //
    431   gBS->CloseEvent (Event);
    432 
    433 }
    434 
    435 
    436 /**
    437   Variable Driver main entry point. The Variable driver places the 4 EFI
    438   runtime services in the EFI System Table and installs arch protocols
    439   for variable read and write services being available. It also registers
    440   a notification function for an EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE event.
    441 
    442   @param[in] ImageHandle    The firmware allocated handle for the EFI image.
    443   @param[in] SystemTable    A pointer to the EFI System Table.
    444 
    445   @retval EFI_SUCCESS       Variable service successfully initialized.
    446 
    447 **/
    448 EFI_STATUS
    449 EFIAPI
    450 VariableServiceInitialize (
    451   IN EFI_HANDLE                         ImageHandle,
    452   IN EFI_SYSTEM_TABLE                   *SystemTable
    453   )
    454 {
    455   EFI_STATUS                            Status;
    456   EFI_EVENT                             ReadyToBootEvent;
    457   EFI_EVENT                             EndOfDxeEvent;
    458 
    459   Status = VariableCommonInitialize ();
    460   ASSERT_EFI_ERROR (Status);
    461 
    462   Status = gBS->InstallMultipleProtocolInterfaces (
    463                   &mHandle,
    464                   &gEdkiiVariableLockProtocolGuid,
    465                   &mVariableLock,
    466                   NULL
    467                   );
    468   ASSERT_EFI_ERROR (Status);
    469 
    470   Status = gBS->InstallMultipleProtocolInterfaces (
    471                   &mHandle,
    472                   &gEdkiiVarCheckProtocolGuid,
    473                   &mVarCheck,
    474                   NULL
    475                   );
    476   ASSERT_EFI_ERROR (Status);
    477 
    478   SystemTable->RuntimeServices->GetVariable         = VariableServiceGetVariable;
    479   SystemTable->RuntimeServices->GetNextVariableName = VariableServiceGetNextVariableName;
    480   SystemTable->RuntimeServices->SetVariable         = VariableServiceSetVariable;
    481   SystemTable->RuntimeServices->QueryVariableInfo   = VariableServiceQueryVariableInfo;
    482 
    483   //
    484   // Now install the Variable Runtime Architectural protocol on a new handle.
    485   //
    486   Status = gBS->InstallProtocolInterface (
    487                   &mHandle,
    488                   &gEfiVariableArchProtocolGuid,
    489                   EFI_NATIVE_INTERFACE,
    490                   NULL
    491                   );
    492   ASSERT_EFI_ERROR (Status);
    493 
    494   //
    495   // Register FtwNotificationEvent () notify function.
    496   //
    497   EfiCreateProtocolNotifyEvent (
    498     &gEfiFaultTolerantWriteProtocolGuid,
    499     TPL_CALLBACK,
    500     FtwNotificationEvent,
    501     (VOID *)SystemTable,
    502     &mFtwRegistration
    503     );
    504 
    505   Status = gBS->CreateEventEx (
    506                   EVT_NOTIFY_SIGNAL,
    507                   TPL_NOTIFY,
    508                   VariableClassAddressChangeEvent,
    509                   NULL,
    510                   &gEfiEventVirtualAddressChangeGuid,
    511                   &mVirtualAddressChangeEvent
    512                   );
    513   ASSERT_EFI_ERROR (Status);
    514 
    515   //
    516   // Register the event handling function to reclaim variable for OS usage.
    517   //
    518   Status = EfiCreateEventReadyToBootEx (
    519              TPL_NOTIFY,
    520              OnReadyToBoot,
    521              NULL,
    522              &ReadyToBootEvent
    523              );
    524   ASSERT_EFI_ERROR (Status);
    525 
    526   //
    527   // Register the event handling function to set the End Of DXE flag.
    528   //
    529   Status = gBS->CreateEventEx (
    530                   EVT_NOTIFY_SIGNAL,
    531                   TPL_NOTIFY,
    532                   OnEndOfDxe,
    533                   NULL,
    534                   &gEfiEndOfDxeEventGroupGuid,
    535                   &EndOfDxeEvent
    536                   );
    537   ASSERT_EFI_ERROR (Status);
    538 
    539   return EFI_SUCCESS;
    540 }
    541 
    542