| /** @file | |
| Functions related to managing the UEFI variable runtime cache. This file should only include functions | |
| used by the SMM UEFI variable driver. | |
| Caution: This module requires additional review when modified. | |
| This driver will have external input - variable data. They may be input in SMM mode. | |
| This external input must be validated carefully to avoid security issue like | |
| buffer overflow, integer overflow. | |
| Copyright (c) 2019, Intel Corporation. All rights reserved.<BR> | |
| SPDX-License-Identifier: BSD-2-Clause-Patent | |
| **/ | |
| #include "VariableParsing.h" | |
| #include "VariableRuntimeCache.h" | |
| extern VARIABLE_MODULE_GLOBAL *mVariableModuleGlobal; | |
| extern VARIABLE_STORE_HEADER *mNvVariableCache; | |
| /** | |
| Copies any pending updates to runtime variable caches. | |
| @retval EFI_UNSUPPORTED The volatile store to be updated is not initialized properly. | |
| @retval EFI_SUCCESS The volatile store was updated successfully. | |
| **/ | |
| EFI_STATUS | |
| FlushPendingRuntimeVariableCacheUpdates ( | |
| VOID | |
| ) | |
| { | |
| VARIABLE_RUNTIME_CACHE_CONTEXT *VariableRuntimeCacheContext; | |
| VariableRuntimeCacheContext = &mVariableModuleGlobal->VariableGlobal.VariableRuntimeCacheContext; | |
| if ((VariableRuntimeCacheContext->VariableRuntimeNvCache.Store == NULL) || | |
| (VariableRuntimeCacheContext->VariableRuntimeVolatileCache.Store == NULL) || | |
| (VariableRuntimeCacheContext->PendingUpdate == NULL)) | |
| { | |
| return EFI_UNSUPPORTED; | |
| } | |
| if (*(VariableRuntimeCacheContext->PendingUpdate)) { | |
| if ((VariableRuntimeCacheContext->VariableRuntimeHobCache.Store != NULL) && | |
| (mVariableModuleGlobal->VariableGlobal.HobVariableBase > 0)) | |
| { | |
| CopyMem ( | |
| (VOID *)( | |
| ((UINT8 *)(UINTN)VariableRuntimeCacheContext->VariableRuntimeHobCache.Store) + | |
| VariableRuntimeCacheContext->VariableRuntimeHobCache.PendingUpdateOffset | |
| ), | |
| (VOID *)( | |
| ((UINT8 *)(UINTN)mVariableModuleGlobal->VariableGlobal.HobVariableBase) + | |
| VariableRuntimeCacheContext->VariableRuntimeHobCache.PendingUpdateOffset | |
| ), | |
| VariableRuntimeCacheContext->VariableRuntimeHobCache.PendingUpdateLength | |
| ); | |
| VariableRuntimeCacheContext->VariableRuntimeHobCache.PendingUpdateLength = 0; | |
| VariableRuntimeCacheContext->VariableRuntimeHobCache.PendingUpdateOffset = 0; | |
| } | |
| CopyMem ( | |
| (VOID *)( | |
| ((UINT8 *)(UINTN)VariableRuntimeCacheContext->VariableRuntimeNvCache.Store) + | |
| VariableRuntimeCacheContext->VariableRuntimeNvCache.PendingUpdateOffset | |
| ), | |
| (VOID *)( | |
| ((UINT8 *)(UINTN)mNvVariableCache) + | |
| VariableRuntimeCacheContext->VariableRuntimeNvCache.PendingUpdateOffset | |
| ), | |
| VariableRuntimeCacheContext->VariableRuntimeNvCache.PendingUpdateLength | |
| ); | |
| VariableRuntimeCacheContext->VariableRuntimeNvCache.PendingUpdateLength = 0; | |
| VariableRuntimeCacheContext->VariableRuntimeNvCache.PendingUpdateOffset = 0; | |
| CopyMem ( | |
| (VOID *)( | |
| ((UINT8 *)(UINTN)VariableRuntimeCacheContext->VariableRuntimeVolatileCache.Store) + | |
| VariableRuntimeCacheContext->VariableRuntimeVolatileCache.PendingUpdateOffset | |
| ), | |
| (VOID *)( | |
| ((UINT8 *)(UINTN)mVariableModuleGlobal->VariableGlobal.VolatileVariableBase) + | |
| VariableRuntimeCacheContext->VariableRuntimeVolatileCache.PendingUpdateOffset | |
| ), | |
| VariableRuntimeCacheContext->VariableRuntimeVolatileCache.PendingUpdateLength | |
| ); | |
| VariableRuntimeCacheContext->VariableRuntimeVolatileCache.PendingUpdateLength = 0; | |
| VariableRuntimeCacheContext->VariableRuntimeVolatileCache.PendingUpdateOffset = 0; | |
| *(VariableRuntimeCacheContext->PendingUpdate) = FALSE; | |
| } | |
| return EFI_SUCCESS; | |
| } | |
| /** | |
| Synchronizes the runtime variable caches with all pending updates outside runtime. | |
| Ensures all conditions are met to maintain coherency for runtime cache updates. This function will attempt | |
| to write the given update (and any other pending updates) if the ReadLock is available. Otherwise, the | |
| update is added as a pending update for the given variable store and it will be flushed to the runtime cache | |
| at the next opportunity the ReadLock is available. | |
| @param[in] VariableRuntimeCache Variable runtime cache structure for the runtime cache being synchronized. | |
| @param[in] Offset Offset in bytes to apply the update. | |
| @param[in] Length Length of data in bytes of the update. | |
| @retval EFI_SUCCESS The update was added as a pending update successfully. If the variable runtime | |
| cache ReadLock was available, the runtime cache was updated successfully. | |
| @retval EFI_UNSUPPORTED The volatile store to be updated is not initialized properly. | |
| **/ | |
| EFI_STATUS | |
| SynchronizeRuntimeVariableCache ( | |
| IN VARIABLE_RUNTIME_CACHE *VariableRuntimeCache, | |
| IN UINTN Offset, | |
| IN UINTN Length | |
| ) | |
| { | |
| if (VariableRuntimeCache == NULL) { | |
| return EFI_INVALID_PARAMETER; | |
| } else if (VariableRuntimeCache->Store == NULL) { | |
| // The runtime cache may not be active or allocated yet. | |
| // In either case, return EFI_SUCCESS instead of EFI_NOT_AVAILABLE_YET. | |
| return EFI_SUCCESS; | |
| } | |
| if ((mVariableModuleGlobal->VariableGlobal.VariableRuntimeCacheContext.PendingUpdate == NULL) || | |
| (mVariableModuleGlobal->VariableGlobal.VariableRuntimeCacheContext.ReadLock == NULL)) | |
| { | |
| return EFI_UNSUPPORTED; | |
| } | |
| if (*(mVariableModuleGlobal->VariableGlobal.VariableRuntimeCacheContext.PendingUpdate) && | |
| (VariableRuntimeCache->PendingUpdateLength > 0)) | |
| { | |
| VariableRuntimeCache->PendingUpdateLength = | |
| (UINT32)( | |
| MAX ( | |
| (UINTN)(VariableRuntimeCache->PendingUpdateOffset + VariableRuntimeCache->PendingUpdateLength), | |
| Offset + Length | |
| ) - MIN ((UINTN)VariableRuntimeCache->PendingUpdateOffset, Offset) | |
| ); | |
| VariableRuntimeCache->PendingUpdateOffset = | |
| (UINT32)MIN ((UINTN)VariableRuntimeCache->PendingUpdateOffset, Offset); | |
| } else { | |
| VariableRuntimeCache->PendingUpdateLength = (UINT32)Length; | |
| VariableRuntimeCache->PendingUpdateOffset = (UINT32)Offset; | |
| } | |
| *(mVariableModuleGlobal->VariableGlobal.VariableRuntimeCacheContext.PendingUpdate) = TRUE; | |
| if (*(mVariableModuleGlobal->VariableGlobal.VariableRuntimeCacheContext.ReadLock) == FALSE) { | |
| return FlushPendingRuntimeVariableCacheUpdates (); | |
| } | |
| return EFI_SUCCESS; | |
| } |