mirror of https://github.com/acidanthera/audk.git
1797 lines
63 KiB
C
1797 lines
63 KiB
C
/** @file
|
|
Implement all four UEFI Runtime Variable services for the nonvolatile
|
|
and volatile storage space and install variable architecture protocol
|
|
based on SMM variable module.
|
|
|
|
Caution: This module requires additional review when modified.
|
|
This driver will have external input - variable data.
|
|
This external input must be validated carefully to avoid security issue like
|
|
buffer overflow, integer overflow.
|
|
|
|
RuntimeServiceGetVariable() and RuntimeServiceSetVariable() are external API
|
|
to receive data buffer. The size should be checked carefully.
|
|
|
|
InitCommunicateBuffer() is really function to check the variable data size.
|
|
|
|
Copyright (c) 2010 - 2019, Intel Corporation. All rights reserved.<BR>
|
|
SPDX-License-Identifier: BSD-2-Clause-Patent
|
|
|
|
**/
|
|
#include <PiDxe.h>
|
|
#include <Protocol/VariableWrite.h>
|
|
#include <Protocol/Variable.h>
|
|
#include <Protocol/SmmCommunication.h>
|
|
#include <Protocol/SmmVariable.h>
|
|
#include <Protocol/VariableLock.h>
|
|
#include <Protocol/VarCheck.h>
|
|
|
|
#include <Library/UefiBootServicesTableLib.h>
|
|
#include <Library/UefiRuntimeServicesTableLib.h>
|
|
#include <Library/MemoryAllocationLib.h>
|
|
#include <Library/UefiDriverEntryPoint.h>
|
|
#include <Library/UefiRuntimeLib.h>
|
|
#include <Library/BaseMemoryLib.h>
|
|
#include <Library/DebugLib.h>
|
|
#include <Library/UefiLib.h>
|
|
#include <Library/BaseLib.h>
|
|
|
|
#include <Guid/EventGroup.h>
|
|
#include <Guid/SmmVariableCommon.h>
|
|
|
|
#include "PrivilegePolymorphic.h"
|
|
#include "VariableParsing.h"
|
|
|
|
EFI_HANDLE mHandle = NULL;
|
|
EFI_SMM_VARIABLE_PROTOCOL *mSmmVariable = NULL;
|
|
EFI_EVENT mVirtualAddressChangeEvent = NULL;
|
|
EFI_SMM_COMMUNICATION_PROTOCOL *mSmmCommunication = NULL;
|
|
UINT8 *mVariableBuffer = NULL;
|
|
UINT8 *mVariableBufferPhysical = NULL;
|
|
VARIABLE_INFO_ENTRY *mVariableInfo = NULL;
|
|
VARIABLE_STORE_HEADER *mVariableRuntimeHobCacheBuffer = NULL;
|
|
VARIABLE_STORE_HEADER *mVariableRuntimeNvCacheBuffer = NULL;
|
|
VARIABLE_STORE_HEADER *mVariableRuntimeVolatileCacheBuffer = NULL;
|
|
UINTN mVariableBufferSize;
|
|
UINTN mVariableRuntimeHobCacheBufferSize;
|
|
UINTN mVariableRuntimeNvCacheBufferSize;
|
|
UINTN mVariableRuntimeVolatileCacheBufferSize;
|
|
UINTN mVariableBufferPayloadSize;
|
|
BOOLEAN mVariableRuntimeCachePendingUpdate;
|
|
BOOLEAN mVariableRuntimeCacheReadLock;
|
|
BOOLEAN mVariableAuthFormat;
|
|
BOOLEAN mHobFlushComplete;
|
|
EFI_LOCK mVariableServicesLock;
|
|
EDKII_VARIABLE_LOCK_PROTOCOL mVariableLock;
|
|
EDKII_VAR_CHECK_PROTOCOL mVarCheck;
|
|
|
|
/**
|
|
Some Secure Boot Policy Variable may update following other variable changes(SecureBoot follows PK change, etc).
|
|
Record their initial State when variable write service is ready.
|
|
|
|
**/
|
|
VOID
|
|
EFIAPI
|
|
RecordSecureBootPolicyVarData(
|
|
VOID
|
|
);
|
|
|
|
/**
|
|
Acquires lock only at boot time. Simply returns at runtime.
|
|
|
|
This is a temperary function that will be removed when
|
|
EfiAcquireLock() in UefiLib can handle the call in UEFI
|
|
Runtimer driver in RT phase.
|
|
It calls EfiAcquireLock() at boot time, and simply returns
|
|
at runtime.
|
|
|
|
@param Lock A pointer to the lock to acquire.
|
|
|
|
**/
|
|
VOID
|
|
AcquireLockOnlyAtBootTime (
|
|
IN EFI_LOCK *Lock
|
|
)
|
|
{
|
|
if (!EfiAtRuntime ()) {
|
|
EfiAcquireLock (Lock);
|
|
}
|
|
}
|
|
|
|
/**
|
|
Releases lock only at boot time. Simply returns at runtime.
|
|
|
|
This is a temperary function which will be removed when
|
|
EfiReleaseLock() in UefiLib can handle the call in UEFI
|
|
Runtimer driver in RT phase.
|
|
It calls EfiReleaseLock() at boot time and simply returns
|
|
at runtime.
|
|
|
|
@param Lock A pointer to the lock to release.
|
|
|
|
**/
|
|
VOID
|
|
ReleaseLockOnlyAtBootTime (
|
|
IN EFI_LOCK *Lock
|
|
)
|
|
{
|
|
if (!EfiAtRuntime ()) {
|
|
EfiReleaseLock (Lock);
|
|
}
|
|
}
|
|
|
|
/**
|
|
Return TRUE if ExitBootServices () has been called.
|
|
|
|
@retval TRUE If ExitBootServices () has been called. FALSE if ExitBootServices () has not been called.
|
|
**/
|
|
BOOLEAN
|
|
AtRuntime (
|
|
VOID
|
|
)
|
|
{
|
|
return EfiAtRuntime ();
|
|
}
|
|
|
|
/**
|
|
Initialize the variable cache buffer as an empty variable store.
|
|
|
|
@param[out] VariableCacheBuffer A pointer to pointer of a cache variable store.
|
|
@param[in,out] TotalVariableCacheSize On input, the minimum size needed for the UEFI variable store cache
|
|
buffer that is allocated. On output, the actual size of the buffer allocated.
|
|
If TotalVariableCacheSize is zero, a buffer will not be allocated and the
|
|
function will return with EFI_SUCCESS.
|
|
|
|
@retval EFI_SUCCESS The variable cache was allocated and initialized successfully.
|
|
@retval EFI_INVALID_PARAMETER A given pointer is NULL or an invalid variable store size was specified.
|
|
@retval EFI_OUT_OF_RESOURCES Insufficient resources are available to allocate the variable store cache buffer.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
InitVariableCache (
|
|
OUT VARIABLE_STORE_HEADER **VariableCacheBuffer,
|
|
IN OUT UINTN *TotalVariableCacheSize
|
|
)
|
|
{
|
|
VARIABLE_STORE_HEADER *VariableCacheStorePtr;
|
|
|
|
if (TotalVariableCacheSize == NULL) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
if (*TotalVariableCacheSize == 0) {
|
|
return EFI_SUCCESS;
|
|
}
|
|
if (VariableCacheBuffer == NULL || *TotalVariableCacheSize < sizeof (VARIABLE_STORE_HEADER)) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
*TotalVariableCacheSize = ALIGN_VALUE (*TotalVariableCacheSize, sizeof (UINT32));
|
|
|
|
//
|
|
// Allocate NV Storage Cache and initialize it to all 1's (like an erased FV)
|
|
//
|
|
*VariableCacheBuffer = (VARIABLE_STORE_HEADER *) AllocateRuntimePages (
|
|
EFI_SIZE_TO_PAGES (*TotalVariableCacheSize)
|
|
);
|
|
if (*VariableCacheBuffer == NULL) {
|
|
return EFI_OUT_OF_RESOURCES;
|
|
}
|
|
VariableCacheStorePtr = *VariableCacheBuffer;
|
|
SetMem32 ((VOID *) VariableCacheStorePtr, *TotalVariableCacheSize, (UINT32) 0xFFFFFFFF);
|
|
|
|
ZeroMem ((VOID *) VariableCacheStorePtr, sizeof (VARIABLE_STORE_HEADER));
|
|
VariableCacheStorePtr->Size = (UINT32) *TotalVariableCacheSize;
|
|
VariableCacheStorePtr->Format = VARIABLE_STORE_FORMATTED;
|
|
VariableCacheStorePtr->State = VARIABLE_STORE_HEALTHY;
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
Initialize the communicate buffer using DataSize and Function.
|
|
|
|
The communicate size is: SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE +
|
|
DataSize.
|
|
|
|
Caution: This function may receive untrusted input.
|
|
The data size external input, so this function will validate it carefully to avoid buffer overflow.
|
|
|
|
@param[out] DataPtr Points to the data in the communicate buffer.
|
|
@param[in] DataSize The data size to send to SMM.
|
|
@param[in] Function The function number to initialize the communicate header.
|
|
|
|
@retval EFI_INVALID_PARAMETER The data size is too big.
|
|
@retval EFI_SUCCESS Find the specified variable.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
InitCommunicateBuffer (
|
|
OUT VOID **DataPtr OPTIONAL,
|
|
IN UINTN DataSize,
|
|
IN UINTN Function
|
|
)
|
|
{
|
|
EFI_SMM_COMMUNICATE_HEADER *SmmCommunicateHeader;
|
|
SMM_VARIABLE_COMMUNICATE_HEADER *SmmVariableFunctionHeader;
|
|
|
|
|
|
if (DataSize + SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE > mVariableBufferSize) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
SmmCommunicateHeader = (EFI_SMM_COMMUNICATE_HEADER *) mVariableBuffer;
|
|
CopyGuid (&SmmCommunicateHeader->HeaderGuid, &gEfiSmmVariableProtocolGuid);
|
|
SmmCommunicateHeader->MessageLength = DataSize + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE;
|
|
|
|
SmmVariableFunctionHeader = (SMM_VARIABLE_COMMUNICATE_HEADER *) SmmCommunicateHeader->Data;
|
|
SmmVariableFunctionHeader->Function = Function;
|
|
if (DataPtr != NULL) {
|
|
*DataPtr = SmmVariableFunctionHeader->Data;
|
|
}
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
|
|
/**
|
|
Send the data in communicate buffer to SMM.
|
|
|
|
@param[in] DataSize This size of the function header and the data.
|
|
|
|
@retval EFI_SUCCESS Success is returned from the functin in SMM.
|
|
@retval Others Failure is returned from the function in SMM.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
SendCommunicateBuffer (
|
|
IN UINTN DataSize
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
UINTN CommSize;
|
|
EFI_SMM_COMMUNICATE_HEADER *SmmCommunicateHeader;
|
|
SMM_VARIABLE_COMMUNICATE_HEADER *SmmVariableFunctionHeader;
|
|
|
|
CommSize = DataSize + SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE;
|
|
Status = mSmmCommunication->Communicate (mSmmCommunication, mVariableBufferPhysical, &CommSize);
|
|
ASSERT_EFI_ERROR (Status);
|
|
|
|
SmmCommunicateHeader = (EFI_SMM_COMMUNICATE_HEADER *) mVariableBuffer;
|
|
SmmVariableFunctionHeader = (SMM_VARIABLE_COMMUNICATE_HEADER *)SmmCommunicateHeader->Data;
|
|
return SmmVariableFunctionHeader->ReturnStatus;
|
|
}
|
|
|
|
/**
|
|
Mark a variable that will become read-only after leaving the DXE phase of execution.
|
|
|
|
@param[in] This The VARIABLE_LOCK_PROTOCOL instance.
|
|
@param[in] VariableName A pointer to the variable name that will be made read-only subsequently.
|
|
@param[in] VendorGuid A pointer to the vendor GUID that will be made read-only subsequently.
|
|
|
|
@retval EFI_SUCCESS The variable specified by the VariableName and the VendorGuid was marked
|
|
as pending to be read-only.
|
|
@retval EFI_INVALID_PARAMETER VariableName or VendorGuid is NULL.
|
|
Or VariableName is an empty string.
|
|
@retval EFI_ACCESS_DENIED EFI_END_OF_DXE_EVENT_GROUP_GUID or EFI_EVENT_GROUP_READY_TO_BOOT has
|
|
already been signaled.
|
|
@retval EFI_OUT_OF_RESOURCES There is not enough resource to hold the lock request.
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
VariableLockRequestToLock (
|
|
IN CONST EDKII_VARIABLE_LOCK_PROTOCOL *This,
|
|
IN CHAR16 *VariableName,
|
|
IN EFI_GUID *VendorGuid
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
UINTN VariableNameSize;
|
|
UINTN PayloadSize;
|
|
SMM_VARIABLE_COMMUNICATE_LOCK_VARIABLE *VariableToLock;
|
|
|
|
if (VariableName == NULL || VariableName[0] == 0 || VendorGuid == NULL) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
VariableNameSize = StrSize (VariableName);
|
|
VariableToLock = NULL;
|
|
|
|
//
|
|
// If VariableName exceeds SMM payload limit. Return failure
|
|
//
|
|
if (VariableNameSize > mVariableBufferPayloadSize - OFFSET_OF (SMM_VARIABLE_COMMUNICATE_LOCK_VARIABLE, Name)) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
AcquireLockOnlyAtBootTime(&mVariableServicesLock);
|
|
|
|
//
|
|
// Init the communicate buffer. The buffer data size is:
|
|
// SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + PayloadSize.
|
|
//
|
|
PayloadSize = OFFSET_OF (SMM_VARIABLE_COMMUNICATE_LOCK_VARIABLE, Name) + VariableNameSize;
|
|
Status = InitCommunicateBuffer ((VOID **) &VariableToLock, PayloadSize, SMM_VARIABLE_FUNCTION_LOCK_VARIABLE);
|
|
if (EFI_ERROR (Status)) {
|
|
goto Done;
|
|
}
|
|
ASSERT (VariableToLock != NULL);
|
|
|
|
CopyGuid (&VariableToLock->Guid, VendorGuid);
|
|
VariableToLock->NameSize = VariableNameSize;
|
|
CopyMem (VariableToLock->Name, VariableName, VariableToLock->NameSize);
|
|
|
|
//
|
|
// Send data to SMM.
|
|
//
|
|
Status = SendCommunicateBuffer (PayloadSize);
|
|
|
|
Done:
|
|
ReleaseLockOnlyAtBootTime (&mVariableServicesLock);
|
|
return Status;
|
|
}
|
|
|
|
/**
|
|
Register SetVariable check handler.
|
|
|
|
@param[in] Handler Pointer to check handler.
|
|
|
|
@retval EFI_SUCCESS The SetVariable check handler was registered successfully.
|
|
@retval EFI_INVALID_PARAMETER Handler is NULL.
|
|
@retval EFI_ACCESS_DENIED EFI_END_OF_DXE_EVENT_GROUP_GUID or EFI_EVENT_GROUP_READY_TO_BOOT has
|
|
already been signaled.
|
|
@retval EFI_OUT_OF_RESOURCES There is not enough resource for the SetVariable check handler register request.
|
|
@retval EFI_UNSUPPORTED This interface is not implemented.
|
|
For example, it is unsupported in VarCheck protocol if both VarCheck and SmmVarCheck protocols are present.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
VarCheckRegisterSetVariableCheckHandler (
|
|
IN VAR_CHECK_SET_VARIABLE_CHECK_HANDLER Handler
|
|
)
|
|
{
|
|
return EFI_UNSUPPORTED;
|
|
}
|
|
|
|
/**
|
|
Variable property set.
|
|
|
|
@param[in] Name Pointer to the variable name.
|
|
@param[in] Guid Pointer to the vendor GUID.
|
|
@param[in] VariableProperty Pointer to the input variable property.
|
|
|
|
@retval EFI_SUCCESS The property of variable specified by the Name and Guid was set successfully.
|
|
@retval EFI_INVALID_PARAMETER Name, Guid or VariableProperty is NULL, or Name is an empty string,
|
|
or the fields of VariableProperty are not valid.
|
|
@retval EFI_ACCESS_DENIED EFI_END_OF_DXE_EVENT_GROUP_GUID or EFI_EVENT_GROUP_READY_TO_BOOT has
|
|
already been signaled.
|
|
@retval EFI_OUT_OF_RESOURCES There is not enough resource for the variable property set request.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
VarCheckVariablePropertySet (
|
|
IN CHAR16 *Name,
|
|
IN EFI_GUID *Guid,
|
|
IN VAR_CHECK_VARIABLE_PROPERTY *VariableProperty
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
UINTN VariableNameSize;
|
|
UINTN PayloadSize;
|
|
SMM_VARIABLE_COMMUNICATE_VAR_CHECK_VARIABLE_PROPERTY *CommVariableProperty;
|
|
|
|
if (Name == NULL || Name[0] == 0 || Guid == NULL) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
if (VariableProperty == NULL) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
if (VariableProperty->Revision != VAR_CHECK_VARIABLE_PROPERTY_REVISION) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
VariableNameSize = StrSize (Name);
|
|
CommVariableProperty = NULL;
|
|
|
|
//
|
|
// If VariableName exceeds SMM payload limit. Return failure
|
|
//
|
|
if (VariableNameSize > mVariableBufferPayloadSize - OFFSET_OF (SMM_VARIABLE_COMMUNICATE_VAR_CHECK_VARIABLE_PROPERTY, Name)) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
AcquireLockOnlyAtBootTime (&mVariableServicesLock);
|
|
|
|
//
|
|
// Init the communicate buffer. The buffer data size is:
|
|
// SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + PayloadSize.
|
|
//
|
|
PayloadSize = OFFSET_OF (SMM_VARIABLE_COMMUNICATE_VAR_CHECK_VARIABLE_PROPERTY, Name) + VariableNameSize;
|
|
Status = InitCommunicateBuffer ((VOID **) &CommVariableProperty, PayloadSize, SMM_VARIABLE_FUNCTION_VAR_CHECK_VARIABLE_PROPERTY_SET);
|
|
if (EFI_ERROR (Status)) {
|
|
goto Done;
|
|
}
|
|
ASSERT (CommVariableProperty != NULL);
|
|
|
|
CopyGuid (&CommVariableProperty->Guid, Guid);
|
|
CopyMem (&CommVariableProperty->VariableProperty, VariableProperty, sizeof (*VariableProperty));
|
|
CommVariableProperty->NameSize = VariableNameSize;
|
|
CopyMem (CommVariableProperty->Name, Name, CommVariableProperty->NameSize);
|
|
|
|
//
|
|
// Send data to SMM.
|
|
//
|
|
Status = SendCommunicateBuffer (PayloadSize);
|
|
|
|
Done:
|
|
ReleaseLockOnlyAtBootTime (&mVariableServicesLock);
|
|
return Status;
|
|
}
|
|
|
|
/**
|
|
Variable property get.
|
|
|
|
@param[in] Name Pointer to the variable name.
|
|
@param[in] Guid Pointer to the vendor GUID.
|
|
@param[out] VariableProperty Pointer to the output variable property.
|
|
|
|
@retval EFI_SUCCESS The property of variable specified by the Name and Guid was got successfully.
|
|
@retval EFI_INVALID_PARAMETER Name, Guid or VariableProperty is NULL, or Name is an empty string.
|
|
@retval EFI_NOT_FOUND The property of variable specified by the Name and Guid was not found.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
VarCheckVariablePropertyGet (
|
|
IN CHAR16 *Name,
|
|
IN EFI_GUID *Guid,
|
|
OUT VAR_CHECK_VARIABLE_PROPERTY *VariableProperty
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
UINTN VariableNameSize;
|
|
UINTN PayloadSize;
|
|
SMM_VARIABLE_COMMUNICATE_VAR_CHECK_VARIABLE_PROPERTY *CommVariableProperty;
|
|
|
|
if (Name == NULL || Name[0] == 0 || Guid == NULL) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
if (VariableProperty == NULL) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
VariableNameSize = StrSize (Name);
|
|
CommVariableProperty = NULL;
|
|
|
|
//
|
|
// If VariableName exceeds SMM payload limit. Return failure
|
|
//
|
|
if (VariableNameSize > mVariableBufferPayloadSize - OFFSET_OF (SMM_VARIABLE_COMMUNICATE_VAR_CHECK_VARIABLE_PROPERTY, Name)) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
AcquireLockOnlyAtBootTime (&mVariableServicesLock);
|
|
|
|
//
|
|
// Init the communicate buffer. The buffer data size is:
|
|
// SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + PayloadSize.
|
|
//
|
|
PayloadSize = OFFSET_OF (SMM_VARIABLE_COMMUNICATE_VAR_CHECK_VARIABLE_PROPERTY, Name) + VariableNameSize;
|
|
Status = InitCommunicateBuffer ((VOID **) &CommVariableProperty, PayloadSize, SMM_VARIABLE_FUNCTION_VAR_CHECK_VARIABLE_PROPERTY_GET);
|
|
if (EFI_ERROR (Status)) {
|
|
goto Done;
|
|
}
|
|
ASSERT (CommVariableProperty != NULL);
|
|
|
|
CopyGuid (&CommVariableProperty->Guid, Guid);
|
|
CommVariableProperty->NameSize = VariableNameSize;
|
|
CopyMem (CommVariableProperty->Name, Name, CommVariableProperty->NameSize);
|
|
|
|
//
|
|
// Send data to SMM.
|
|
//
|
|
Status = SendCommunicateBuffer (PayloadSize);
|
|
if (Status == EFI_SUCCESS) {
|
|
CopyMem (VariableProperty, &CommVariableProperty->VariableProperty, sizeof (*VariableProperty));
|
|
}
|
|
|
|
Done:
|
|
ReleaseLockOnlyAtBootTime (&mVariableServicesLock);
|
|
return Status;
|
|
}
|
|
|
|
/**
|
|
Signals SMM to synchronize any pending variable updates with the runtime cache(s).
|
|
|
|
**/
|
|
VOID
|
|
SyncRuntimeCache (
|
|
VOID
|
|
)
|
|
{
|
|
//
|
|
// Init the communicate buffer. The buffer data size is:
|
|
// SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE.
|
|
//
|
|
InitCommunicateBuffer (NULL, 0, SMM_VARIABLE_FUNCTION_SYNC_RUNTIME_CACHE);
|
|
|
|
//
|
|
// Send data to SMM.
|
|
//
|
|
SendCommunicateBuffer (0);
|
|
}
|
|
|
|
/**
|
|
Check whether a SMI must be triggered to retrieve pending cache updates.
|
|
|
|
If the variable HOB was finished being flushed since the last check for a runtime cache update, this function
|
|
will prevent the HOB cache from being used for future runtime cache hits.
|
|
|
|
**/
|
|
VOID
|
|
CheckForRuntimeCacheSync (
|
|
VOID
|
|
)
|
|
{
|
|
if (mVariableRuntimeCachePendingUpdate) {
|
|
SyncRuntimeCache ();
|
|
}
|
|
ASSERT (!mVariableRuntimeCachePendingUpdate);
|
|
|
|
//
|
|
// The HOB variable data may have finished being flushed in the runtime cache sync update
|
|
//
|
|
if (mHobFlushComplete && mVariableRuntimeHobCacheBuffer != NULL) {
|
|
if (!EfiAtRuntime ()) {
|
|
FreePages (mVariableRuntimeHobCacheBuffer, EFI_SIZE_TO_PAGES (mVariableRuntimeHobCacheBufferSize));
|
|
}
|
|
mVariableRuntimeHobCacheBuffer = NULL;
|
|
}
|
|
}
|
|
|
|
/**
|
|
Finds the given variable in a runtime cache variable store.
|
|
|
|
Caution: This function may receive untrusted input.
|
|
The data size is external input, so this function will validate it carefully to avoid buffer overflow.
|
|
|
|
@param[in] VariableName Name of Variable to be found.
|
|
@param[in] VendorGuid Variable vendor GUID.
|
|
@param[out] Attributes Attribute value of the variable found.
|
|
@param[in, out] DataSize Size of Data found. If size is less than the
|
|
data, this value contains the required size.
|
|
@param[out] Data Data pointer.
|
|
|
|
@retval EFI_SUCCESS Found the specified variable.
|
|
@retval EFI_INVALID_PARAMETER Invalid parameter.
|
|
@retval EFI_NOT_FOUND The specified variable could not be found.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
FindVariableInRuntimeCache (
|
|
IN CHAR16 *VariableName,
|
|
IN EFI_GUID *VendorGuid,
|
|
OUT UINT32 *Attributes OPTIONAL,
|
|
IN OUT UINTN *DataSize,
|
|
OUT VOID *Data OPTIONAL
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
UINTN TempDataSize;
|
|
VARIABLE_POINTER_TRACK RtPtrTrack;
|
|
VARIABLE_STORE_TYPE StoreType;
|
|
VARIABLE_STORE_HEADER *VariableStoreList[VariableStoreTypeMax];
|
|
|
|
Status = EFI_NOT_FOUND;
|
|
|
|
if (VariableName == NULL || VendorGuid == NULL || DataSize == NULL) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
ZeroMem (&RtPtrTrack, sizeof (RtPtrTrack));
|
|
|
|
//
|
|
// The UEFI specification restricts Runtime Services callers from invoking the same or certain other Runtime Service
|
|
// functions prior to completion and return from a previous Runtime Service call. These restrictions prevent
|
|
// a GetVariable () or GetNextVariable () call from being issued until a prior call has returned. The runtime
|
|
// cache read lock should always be free when entering this function.
|
|
//
|
|
ASSERT (!mVariableRuntimeCacheReadLock);
|
|
|
|
mVariableRuntimeCacheReadLock = TRUE;
|
|
CheckForRuntimeCacheSync ();
|
|
|
|
if (!mVariableRuntimeCachePendingUpdate) {
|
|
//
|
|
// 0: Volatile, 1: HOB, 2: Non-Volatile.
|
|
// The index and attributes mapping must be kept in this order as FindVariable
|
|
// makes use of this mapping to implement search algorithm.
|
|
//
|
|
VariableStoreList[VariableStoreTypeVolatile] = mVariableRuntimeVolatileCacheBuffer;
|
|
VariableStoreList[VariableStoreTypeHob] = mVariableRuntimeHobCacheBuffer;
|
|
VariableStoreList[VariableStoreTypeNv] = mVariableRuntimeNvCacheBuffer;
|
|
|
|
for (StoreType = (VARIABLE_STORE_TYPE) 0; StoreType < VariableStoreTypeMax; StoreType++) {
|
|
if (VariableStoreList[StoreType] == NULL) {
|
|
continue;
|
|
}
|
|
|
|
RtPtrTrack.StartPtr = GetStartPointer (VariableStoreList[StoreType]);
|
|
RtPtrTrack.EndPtr = GetEndPointer (VariableStoreList[StoreType]);
|
|
RtPtrTrack.Volatile = (BOOLEAN) (StoreType == VariableStoreTypeVolatile);
|
|
|
|
Status = FindVariableEx (VariableName, VendorGuid, FALSE, &RtPtrTrack, mVariableAuthFormat);
|
|
if (!EFI_ERROR (Status)) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (!EFI_ERROR (Status)) {
|
|
//
|
|
// Get data size
|
|
//
|
|
TempDataSize = DataSizeOfVariable (RtPtrTrack.CurrPtr, mVariableAuthFormat);
|
|
ASSERT (TempDataSize != 0);
|
|
|
|
if (*DataSize >= TempDataSize) {
|
|
if (Data == NULL) {
|
|
Status = EFI_INVALID_PARAMETER;
|
|
goto Done;
|
|
}
|
|
|
|
CopyMem (Data, GetVariableDataPtr (RtPtrTrack.CurrPtr, mVariableAuthFormat), TempDataSize);
|
|
if (Attributes != NULL) {
|
|
*Attributes = RtPtrTrack.CurrPtr->Attributes;
|
|
}
|
|
|
|
*DataSize = TempDataSize;
|
|
|
|
UpdateVariableInfo (VariableName, VendorGuid, RtPtrTrack.Volatile, TRUE, FALSE, FALSE, TRUE, &mVariableInfo);
|
|
|
|
Status = EFI_SUCCESS;
|
|
goto Done;
|
|
} else {
|
|
*DataSize = TempDataSize;
|
|
Status = EFI_BUFFER_TOO_SMALL;
|
|
goto Done;
|
|
}
|
|
}
|
|
}
|
|
|
|
Done:
|
|
mVariableRuntimeCacheReadLock = FALSE;
|
|
|
|
return Status;
|
|
}
|
|
|
|
/**
|
|
Finds the given variable in a variable store in SMM.
|
|
|
|
Caution: This function may receive untrusted input.
|
|
The data size is external input, so this function will validate it carefully to avoid buffer overflow.
|
|
|
|
@param[in] VariableName Name of Variable to be found.
|
|
@param[in] VendorGuid Variable vendor GUID.
|
|
@param[out] Attributes Attribute value of the variable found.
|
|
@param[in, out] DataSize Size of Data found. If size is less than the
|
|
data, this value contains the required size.
|
|
@param[out] Data Data pointer.
|
|
|
|
@retval EFI_SUCCESS Found the specified variable.
|
|
@retval EFI_INVALID_PARAMETER Invalid parameter.
|
|
@retval EFI_NOT_FOUND The specified variable could not be found.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
FindVariableInSmm (
|
|
IN CHAR16 *VariableName,
|
|
IN EFI_GUID *VendorGuid,
|
|
OUT UINT32 *Attributes OPTIONAL,
|
|
IN OUT UINTN *DataSize,
|
|
OUT VOID *Data OPTIONAL
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
UINTN PayloadSize;
|
|
SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE *SmmVariableHeader;
|
|
UINTN TempDataSize;
|
|
UINTN VariableNameSize;
|
|
|
|
if (VariableName == NULL || VendorGuid == NULL || DataSize == NULL) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
TempDataSize = *DataSize;
|
|
VariableNameSize = StrSize (VariableName);
|
|
SmmVariableHeader = NULL;
|
|
|
|
//
|
|
// If VariableName exceeds SMM payload limit. Return failure
|
|
//
|
|
if (VariableNameSize > mVariableBufferPayloadSize - OFFSET_OF (SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE, Name)) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
//
|
|
// Init the communicate buffer. The buffer data size is:
|
|
// SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + PayloadSize.
|
|
//
|
|
if (TempDataSize > mVariableBufferPayloadSize - OFFSET_OF (SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE, Name) - VariableNameSize) {
|
|
//
|
|
// If output data buffer exceed SMM payload limit. Trim output buffer to SMM payload size
|
|
//
|
|
TempDataSize = mVariableBufferPayloadSize - OFFSET_OF (SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE, Name) - VariableNameSize;
|
|
}
|
|
PayloadSize = OFFSET_OF (SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE, Name) + VariableNameSize + TempDataSize;
|
|
|
|
Status = InitCommunicateBuffer ((VOID **) &SmmVariableHeader, PayloadSize, SMM_VARIABLE_FUNCTION_GET_VARIABLE);
|
|
if (EFI_ERROR (Status)) {
|
|
goto Done;
|
|
}
|
|
ASSERT (SmmVariableHeader != NULL);
|
|
|
|
CopyGuid (&SmmVariableHeader->Guid, VendorGuid);
|
|
SmmVariableHeader->DataSize = TempDataSize;
|
|
SmmVariableHeader->NameSize = VariableNameSize;
|
|
if (Attributes == NULL) {
|
|
SmmVariableHeader->Attributes = 0;
|
|
} else {
|
|
SmmVariableHeader->Attributes = *Attributes;
|
|
}
|
|
CopyMem (SmmVariableHeader->Name, VariableName, SmmVariableHeader->NameSize);
|
|
|
|
//
|
|
// Send data to SMM.
|
|
//
|
|
Status = SendCommunicateBuffer (PayloadSize);
|
|
|
|
//
|
|
// Get data from SMM.
|
|
//
|
|
if (Status == EFI_SUCCESS || Status == EFI_BUFFER_TOO_SMALL) {
|
|
//
|
|
// SMM CommBuffer DataSize can be a trimed value
|
|
// Only update DataSize when needed
|
|
//
|
|
*DataSize = SmmVariableHeader->DataSize;
|
|
}
|
|
if (Attributes != NULL) {
|
|
*Attributes = SmmVariableHeader->Attributes;
|
|
}
|
|
|
|
if (EFI_ERROR (Status)) {
|
|
goto Done;
|
|
}
|
|
|
|
if (Data != NULL) {
|
|
CopyMem (Data, (UINT8 *)SmmVariableHeader->Name + SmmVariableHeader->NameSize, SmmVariableHeader->DataSize);
|
|
} else {
|
|
Status = EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
Done:
|
|
return Status;
|
|
}
|
|
|
|
/**
|
|
This code finds variable in storage blocks (Volatile or Non-Volatile).
|
|
|
|
Caution: This function may receive untrusted input.
|
|
The data size is external input, so this function will validate it carefully to avoid buffer overflow.
|
|
|
|
@param[in] VariableName Name of Variable to be found.
|
|
@param[in] VendorGuid Variable vendor GUID.
|
|
@param[out] Attributes Attribute value of the variable found.
|
|
@param[in, out] DataSize Size of Data found. If size is less than the
|
|
data, this value contains the required size.
|
|
@param[out] Data Data pointer.
|
|
|
|
@retval EFI_INVALID_PARAMETER Invalid parameter.
|
|
@retval EFI_SUCCESS Find the specified variable.
|
|
@retval EFI_NOT_FOUND Not found.
|
|
@retval EFI_BUFFER_TO_SMALL DataSize is too small for the result.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
RuntimeServiceGetVariable (
|
|
IN CHAR16 *VariableName,
|
|
IN EFI_GUID *VendorGuid,
|
|
OUT UINT32 *Attributes OPTIONAL,
|
|
IN OUT UINTN *DataSize,
|
|
OUT VOID *Data
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
|
|
if (VariableName == NULL || VendorGuid == NULL || DataSize == NULL) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
if (VariableName[0] == 0) {
|
|
return EFI_NOT_FOUND;
|
|
}
|
|
|
|
AcquireLockOnlyAtBootTime (&mVariableServicesLock);
|
|
if (FeaturePcdGet (PcdEnableVariableRuntimeCache)) {
|
|
Status = FindVariableInRuntimeCache (VariableName, VendorGuid, Attributes, DataSize, Data);
|
|
} else {
|
|
Status = FindVariableInSmm (VariableName, VendorGuid, Attributes, DataSize, Data);
|
|
}
|
|
ReleaseLockOnlyAtBootTime (&mVariableServicesLock);
|
|
|
|
return Status;
|
|
}
|
|
|
|
/**
|
|
Finds the next available variable in a runtime cache variable store.
|
|
|
|
@param[in, out] VariableNameSize Size of the variable name.
|
|
@param[in, out] VariableName Pointer to variable name.
|
|
@param[in, out] VendorGuid Variable Vendor Guid.
|
|
|
|
@retval EFI_INVALID_PARAMETER Invalid parameter.
|
|
@retval EFI_SUCCESS Find the specified variable.
|
|
@retval EFI_NOT_FOUND Not found.
|
|
@retval EFI_BUFFER_TO_SMALL DataSize is too small for the result.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
GetNextVariableNameInRuntimeCache (
|
|
IN OUT UINTN *VariableNameSize,
|
|
IN OUT CHAR16 *VariableName,
|
|
IN OUT EFI_GUID *VendorGuid
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
UINTN VarNameSize;
|
|
VARIABLE_HEADER *VariablePtr;
|
|
VARIABLE_STORE_HEADER *VariableStoreHeader[VariableStoreTypeMax];
|
|
|
|
Status = EFI_NOT_FOUND;
|
|
|
|
//
|
|
// The UEFI specification restricts Runtime Services callers from invoking the same or certain other Runtime Service
|
|
// functions prior to completion and return from a previous Runtime Service call. These restrictions prevent
|
|
// a GetVariable () or GetNextVariable () call from being issued until a prior call has returned. The runtime
|
|
// cache read lock should always be free when entering this function.
|
|
//
|
|
ASSERT (!mVariableRuntimeCacheReadLock);
|
|
|
|
CheckForRuntimeCacheSync ();
|
|
|
|
mVariableRuntimeCacheReadLock = TRUE;
|
|
if (!mVariableRuntimeCachePendingUpdate) {
|
|
//
|
|
// 0: Volatile, 1: HOB, 2: Non-Volatile.
|
|
// The index and attributes mapping must be kept in this order as FindVariable
|
|
// makes use of this mapping to implement search algorithm.
|
|
//
|
|
VariableStoreHeader[VariableStoreTypeVolatile] = mVariableRuntimeVolatileCacheBuffer;
|
|
VariableStoreHeader[VariableStoreTypeHob] = mVariableRuntimeHobCacheBuffer;
|
|
VariableStoreHeader[VariableStoreTypeNv] = mVariableRuntimeNvCacheBuffer;
|
|
|
|
Status = VariableServiceGetNextVariableInternal (
|
|
VariableName,
|
|
VendorGuid,
|
|
VariableStoreHeader,
|
|
&VariablePtr,
|
|
mVariableAuthFormat
|
|
);
|
|
if (!EFI_ERROR (Status)) {
|
|
VarNameSize = NameSizeOfVariable (VariablePtr, mVariableAuthFormat);
|
|
ASSERT (VarNameSize != 0);
|
|
if (VarNameSize <= *VariableNameSize) {
|
|
CopyMem (VariableName, GetVariableNamePtr (VariablePtr, mVariableAuthFormat), VarNameSize);
|
|
CopyMem (VendorGuid, GetVendorGuidPtr (VariablePtr, mVariableAuthFormat), sizeof (EFI_GUID));
|
|
Status = EFI_SUCCESS;
|
|
} else {
|
|
Status = EFI_BUFFER_TOO_SMALL;
|
|
}
|
|
|
|
*VariableNameSize = VarNameSize;
|
|
}
|
|
}
|
|
mVariableRuntimeCacheReadLock = FALSE;
|
|
|
|
return Status;
|
|
}
|
|
|
|
/**
|
|
Finds the next available variable in a SMM variable store.
|
|
|
|
@param[in, out] VariableNameSize Size of the variable name.
|
|
@param[in, out] VariableName Pointer to variable name.
|
|
@param[in, out] VendorGuid Variable Vendor Guid.
|
|
|
|
@retval EFI_INVALID_PARAMETER Invalid parameter.
|
|
@retval EFI_SUCCESS Find the specified variable.
|
|
@retval EFI_NOT_FOUND Not found.
|
|
@retval EFI_BUFFER_TO_SMALL DataSize is too small for the result.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
GetNextVariableNameInSmm (
|
|
IN OUT UINTN *VariableNameSize,
|
|
IN OUT CHAR16 *VariableName,
|
|
IN OUT EFI_GUID *VendorGuid
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
UINTN PayloadSize;
|
|
SMM_VARIABLE_COMMUNICATE_GET_NEXT_VARIABLE_NAME *SmmGetNextVariableName;
|
|
UINTN OutVariableNameSize;
|
|
UINTN InVariableNameSize;
|
|
|
|
OutVariableNameSize = *VariableNameSize;
|
|
InVariableNameSize = StrSize (VariableName);
|
|
SmmGetNextVariableName = NULL;
|
|
|
|
//
|
|
// If input string exceeds SMM payload limit. Return failure
|
|
//
|
|
if (InVariableNameSize > mVariableBufferPayloadSize - OFFSET_OF (SMM_VARIABLE_COMMUNICATE_GET_NEXT_VARIABLE_NAME, Name)) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
//
|
|
// Init the communicate buffer. The buffer data size is:
|
|
// SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + PayloadSize.
|
|
//
|
|
if (OutVariableNameSize > mVariableBufferPayloadSize - OFFSET_OF (SMM_VARIABLE_COMMUNICATE_GET_NEXT_VARIABLE_NAME, Name)) {
|
|
//
|
|
// If output buffer exceed SMM payload limit. Trim output buffer to SMM payload size
|
|
//
|
|
OutVariableNameSize = mVariableBufferPayloadSize - OFFSET_OF (SMM_VARIABLE_COMMUNICATE_GET_NEXT_VARIABLE_NAME, Name);
|
|
}
|
|
//
|
|
// Payload should be Guid + NameSize + MAX of Input & Output buffer
|
|
//
|
|
PayloadSize = OFFSET_OF (SMM_VARIABLE_COMMUNICATE_GET_NEXT_VARIABLE_NAME, Name) + MAX (OutVariableNameSize, InVariableNameSize);
|
|
|
|
Status = InitCommunicateBuffer ((VOID **)&SmmGetNextVariableName, PayloadSize, SMM_VARIABLE_FUNCTION_GET_NEXT_VARIABLE_NAME);
|
|
if (EFI_ERROR (Status)) {
|
|
goto Done;
|
|
}
|
|
ASSERT (SmmGetNextVariableName != NULL);
|
|
|
|
//
|
|
// SMM comm buffer->NameSize is buffer size for return string
|
|
//
|
|
SmmGetNextVariableName->NameSize = OutVariableNameSize;
|
|
|
|
CopyGuid (&SmmGetNextVariableName->Guid, VendorGuid);
|
|
//
|
|
// Copy whole string
|
|
//
|
|
CopyMem (SmmGetNextVariableName->Name, VariableName, InVariableNameSize);
|
|
if (OutVariableNameSize > InVariableNameSize) {
|
|
ZeroMem ((UINT8 *) SmmGetNextVariableName->Name + InVariableNameSize, OutVariableNameSize - InVariableNameSize);
|
|
}
|
|
|
|
//
|
|
// Send data to SMM
|
|
//
|
|
Status = SendCommunicateBuffer (PayloadSize);
|
|
|
|
//
|
|
// Get data from SMM.
|
|
//
|
|
if (Status == EFI_SUCCESS || Status == EFI_BUFFER_TOO_SMALL) {
|
|
//
|
|
// SMM CommBuffer NameSize can be a trimed value
|
|
// Only update VariableNameSize when needed
|
|
//
|
|
*VariableNameSize = SmmGetNextVariableName->NameSize;
|
|
}
|
|
if (EFI_ERROR (Status)) {
|
|
goto Done;
|
|
}
|
|
|
|
CopyGuid (VendorGuid, &SmmGetNextVariableName->Guid);
|
|
CopyMem (VariableName, SmmGetNextVariableName->Name, SmmGetNextVariableName->NameSize);
|
|
|
|
Done:
|
|
return Status;
|
|
}
|
|
|
|
/**
|
|
This code Finds the Next available variable.
|
|
|
|
@param[in, out] VariableNameSize Size of the variable name.
|
|
@param[in, out] VariableName Pointer to variable name.
|
|
@param[in, out] VendorGuid Variable Vendor Guid.
|
|
|
|
@retval EFI_INVALID_PARAMETER Invalid parameter.
|
|
@retval EFI_SUCCESS Find the specified variable.
|
|
@retval EFI_NOT_FOUND Not found.
|
|
@retval EFI_BUFFER_TO_SMALL DataSize is too small for the result.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
RuntimeServiceGetNextVariableName (
|
|
IN OUT UINTN *VariableNameSize,
|
|
IN OUT CHAR16 *VariableName,
|
|
IN OUT EFI_GUID *VendorGuid
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
UINTN MaxLen;
|
|
|
|
Status = EFI_NOT_FOUND;
|
|
|
|
if (VariableNameSize == NULL || VariableName == NULL || VendorGuid == NULL) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
//
|
|
// Calculate the possible maximum length of name string, including the Null terminator.
|
|
//
|
|
MaxLen = *VariableNameSize / sizeof (CHAR16);
|
|
if ((MaxLen == 0) || (StrnLenS (VariableName, MaxLen) == MaxLen)) {
|
|
//
|
|
// Null-terminator is not found in the first VariableNameSize bytes of the input VariableName buffer,
|
|
// follow spec to return EFI_INVALID_PARAMETER.
|
|
//
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
AcquireLockOnlyAtBootTime (&mVariableServicesLock);
|
|
if (FeaturePcdGet (PcdEnableVariableRuntimeCache)) {
|
|
Status = GetNextVariableNameInRuntimeCache (VariableNameSize, VariableName, VendorGuid);
|
|
} else {
|
|
Status = GetNextVariableNameInSmm (VariableNameSize, VariableName, VendorGuid);
|
|
}
|
|
ReleaseLockOnlyAtBootTime (&mVariableServicesLock);
|
|
|
|
return Status;
|
|
}
|
|
|
|
/**
|
|
This code sets variable in storage blocks (Volatile or Non-Volatile).
|
|
|
|
Caution: This function may receive untrusted input.
|
|
The data size and data are external input, so this function will validate it carefully to avoid buffer overflow.
|
|
|
|
@param[in] VariableName Name of Variable to be found.
|
|
@param[in] VendorGuid Variable vendor GUID.
|
|
@param[in] Attributes Attribute value of the variable found
|
|
@param[in] DataSize Size of Data found. If size is less than the
|
|
data, this value contains the required size.
|
|
@param[in] Data Data pointer.
|
|
|
|
@retval EFI_INVALID_PARAMETER Invalid parameter.
|
|
@retval EFI_SUCCESS Set successfully.
|
|
@retval EFI_OUT_OF_RESOURCES Resource not enough to set variable.
|
|
@retval EFI_NOT_FOUND Not found.
|
|
@retval EFI_WRITE_PROTECTED Variable is read-only.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
RuntimeServiceSetVariable (
|
|
IN CHAR16 *VariableName,
|
|
IN EFI_GUID *VendorGuid,
|
|
IN UINT32 Attributes,
|
|
IN UINTN DataSize,
|
|
IN VOID *Data
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
UINTN PayloadSize;
|
|
SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE *SmmVariableHeader;
|
|
UINTN VariableNameSize;
|
|
|
|
//
|
|
// Check input parameters.
|
|
//
|
|
if (VariableName == NULL || VariableName[0] == 0 || VendorGuid == NULL) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
if (DataSize != 0 && Data == NULL) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
VariableNameSize = StrSize (VariableName);
|
|
SmmVariableHeader = NULL;
|
|
|
|
//
|
|
// If VariableName or DataSize exceeds SMM payload limit. Return failure
|
|
//
|
|
if ((VariableNameSize > mVariableBufferPayloadSize - OFFSET_OF (SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE, Name)) ||
|
|
(DataSize > mVariableBufferPayloadSize - OFFSET_OF (SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE, Name) - VariableNameSize)){
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
AcquireLockOnlyAtBootTime(&mVariableServicesLock);
|
|
|
|
//
|
|
// Init the communicate buffer. The buffer data size is:
|
|
// SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + PayloadSize.
|
|
//
|
|
PayloadSize = OFFSET_OF (SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE, Name) + VariableNameSize + DataSize;
|
|
Status = InitCommunicateBuffer ((VOID **)&SmmVariableHeader, PayloadSize, SMM_VARIABLE_FUNCTION_SET_VARIABLE);
|
|
if (EFI_ERROR (Status)) {
|
|
goto Done;
|
|
}
|
|
ASSERT (SmmVariableHeader != NULL);
|
|
|
|
CopyGuid ((EFI_GUID *) &SmmVariableHeader->Guid, VendorGuid);
|
|
SmmVariableHeader->DataSize = DataSize;
|
|
SmmVariableHeader->NameSize = VariableNameSize;
|
|
SmmVariableHeader->Attributes = Attributes;
|
|
CopyMem (SmmVariableHeader->Name, VariableName, SmmVariableHeader->NameSize);
|
|
CopyMem ((UINT8 *) SmmVariableHeader->Name + SmmVariableHeader->NameSize, Data, DataSize);
|
|
|
|
//
|
|
// Send data to SMM.
|
|
//
|
|
Status = SendCommunicateBuffer (PayloadSize);
|
|
|
|
Done:
|
|
ReleaseLockOnlyAtBootTime (&mVariableServicesLock);
|
|
|
|
if (!EfiAtRuntime ()) {
|
|
if (!EFI_ERROR (Status)) {
|
|
SecureBootHook (
|
|
VariableName,
|
|
VendorGuid
|
|
);
|
|
}
|
|
}
|
|
return Status;
|
|
}
|
|
|
|
|
|
/**
|
|
This code returns information about the EFI variables.
|
|
|
|
@param[in] Attributes Attributes bitmask to specify the type of variables
|
|
on which to return information.
|
|
@param[out] MaximumVariableStorageSize Pointer to the maximum size of the storage space available
|
|
for the EFI variables associated with the attributes specified.
|
|
@param[out] RemainingVariableStorageSize Pointer to the remaining size of the storage space available
|
|
for EFI variables associated with the attributes specified.
|
|
@param[out] MaximumVariableSize Pointer to the maximum size of an individual EFI variables
|
|
associated with the attributes specified.
|
|
|
|
@retval EFI_INVALID_PARAMETER An invalid combination of attribute bits was supplied.
|
|
@retval EFI_SUCCESS Query successfully.
|
|
@retval EFI_UNSUPPORTED The attribute is not supported on this platform.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
RuntimeServiceQueryVariableInfo (
|
|
IN UINT32 Attributes,
|
|
OUT UINT64 *MaximumVariableStorageSize,
|
|
OUT UINT64 *RemainingVariableStorageSize,
|
|
OUT UINT64 *MaximumVariableSize
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
UINTN PayloadSize;
|
|
SMM_VARIABLE_COMMUNICATE_QUERY_VARIABLE_INFO *SmmQueryVariableInfo;
|
|
|
|
SmmQueryVariableInfo = NULL;
|
|
|
|
if(MaximumVariableStorageSize == NULL || RemainingVariableStorageSize == NULL || MaximumVariableSize == NULL || Attributes == 0) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
AcquireLockOnlyAtBootTime(&mVariableServicesLock);
|
|
|
|
//
|
|
// Init the communicate buffer. The buffer data size is:
|
|
// SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + PayloadSize;
|
|
//
|
|
PayloadSize = sizeof (SMM_VARIABLE_COMMUNICATE_QUERY_VARIABLE_INFO);
|
|
Status = InitCommunicateBuffer ((VOID **)&SmmQueryVariableInfo, PayloadSize, SMM_VARIABLE_FUNCTION_QUERY_VARIABLE_INFO);
|
|
if (EFI_ERROR (Status)) {
|
|
goto Done;
|
|
}
|
|
ASSERT (SmmQueryVariableInfo != NULL);
|
|
|
|
SmmQueryVariableInfo->Attributes = Attributes;
|
|
|
|
//
|
|
// Send data to SMM.
|
|
//
|
|
Status = SendCommunicateBuffer (PayloadSize);
|
|
if (EFI_ERROR (Status)) {
|
|
goto Done;
|
|
}
|
|
|
|
//
|
|
// Get data from SMM.
|
|
//
|
|
*MaximumVariableSize = SmmQueryVariableInfo->MaximumVariableSize;
|
|
*MaximumVariableStorageSize = SmmQueryVariableInfo->MaximumVariableStorageSize;
|
|
*RemainingVariableStorageSize = SmmQueryVariableInfo->RemainingVariableStorageSize;
|
|
|
|
Done:
|
|
ReleaseLockOnlyAtBootTime (&mVariableServicesLock);
|
|
return Status;
|
|
}
|
|
|
|
|
|
/**
|
|
Exit Boot Services Event notification handler.
|
|
|
|
Notify SMM variable driver about the event.
|
|
|
|
@param[in] Event Event whose notification function is being invoked.
|
|
@param[in] Context Pointer to the notification function's context.
|
|
|
|
**/
|
|
VOID
|
|
EFIAPI
|
|
OnExitBootServices (
|
|
IN EFI_EVENT Event,
|
|
IN VOID *Context
|
|
)
|
|
{
|
|
//
|
|
// Init the communicate buffer. The buffer data size is:
|
|
// SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE.
|
|
//
|
|
InitCommunicateBuffer (NULL, 0, SMM_VARIABLE_FUNCTION_EXIT_BOOT_SERVICE);
|
|
|
|
//
|
|
// Send data to SMM.
|
|
//
|
|
SendCommunicateBuffer (0);
|
|
}
|
|
|
|
|
|
/**
|
|
On Ready To Boot Services Event notification handler.
|
|
|
|
Notify SMM variable driver about the event.
|
|
|
|
@param[in] Event Event whose notification function is being invoked
|
|
@param[in] Context Pointer to the notification function's context
|
|
|
|
**/
|
|
VOID
|
|
EFIAPI
|
|
OnReadyToBoot (
|
|
IN EFI_EVENT Event,
|
|
IN VOID *Context
|
|
)
|
|
{
|
|
//
|
|
// Init the communicate buffer. The buffer data size is:
|
|
// SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE.
|
|
//
|
|
InitCommunicateBuffer (NULL, 0, SMM_VARIABLE_FUNCTION_READY_TO_BOOT);
|
|
|
|
//
|
|
// Send data to SMM.
|
|
//
|
|
SendCommunicateBuffer (0);
|
|
|
|
//
|
|
// Install the system configuration table for variable info data captured
|
|
//
|
|
if (FeaturePcdGet (PcdEnableVariableRuntimeCache) && FeaturePcdGet (PcdVariableCollectStatistics)) {
|
|
if (mVariableAuthFormat) {
|
|
gBS->InstallConfigurationTable (&gEfiAuthenticatedVariableGuid, mVariableInfo);
|
|
} else {
|
|
gBS->InstallConfigurationTable (&gEfiVariableGuid, mVariableInfo);
|
|
}
|
|
}
|
|
|
|
gBS->CloseEvent (Event);
|
|
}
|
|
|
|
|
|
/**
|
|
Notification function of EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE.
|
|
|
|
This is a notification function registered on EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE event.
|
|
It convers pointer to new virtual address.
|
|
|
|
@param[in] Event Event whose notification function is being invoked.
|
|
@param[in] Context Pointer to the notification function's context.
|
|
|
|
**/
|
|
VOID
|
|
EFIAPI
|
|
VariableAddressChangeEvent (
|
|
IN EFI_EVENT Event,
|
|
IN VOID *Context
|
|
)
|
|
{
|
|
EfiConvertPointer (0x0, (VOID **) &mVariableBuffer);
|
|
EfiConvertPointer (0x0, (VOID **) &mSmmCommunication);
|
|
EfiConvertPointer (EFI_OPTIONAL_PTR, (VOID **) &mVariableRuntimeHobCacheBuffer);
|
|
EfiConvertPointer (EFI_OPTIONAL_PTR, (VOID **) &mVariableRuntimeNvCacheBuffer);
|
|
EfiConvertPointer (EFI_OPTIONAL_PTR, (VOID **) &mVariableRuntimeVolatileCacheBuffer);
|
|
}
|
|
|
|
/**
|
|
This code gets variable payload size.
|
|
|
|
@param[out] VariablePayloadSize Output pointer to variable payload size.
|
|
|
|
@retval EFI_SUCCESS Get successfully.
|
|
@retval Others Get unsuccessfully.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
GetVariablePayloadSize (
|
|
OUT UINTN *VariablePayloadSize
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
SMM_VARIABLE_COMMUNICATE_GET_PAYLOAD_SIZE *SmmGetPayloadSize;
|
|
EFI_SMM_COMMUNICATE_HEADER *SmmCommunicateHeader;
|
|
SMM_VARIABLE_COMMUNICATE_HEADER *SmmVariableFunctionHeader;
|
|
UINTN CommSize;
|
|
UINT8 *CommBuffer;
|
|
|
|
SmmGetPayloadSize = NULL;
|
|
CommBuffer = NULL;
|
|
|
|
if(VariablePayloadSize == NULL) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
AcquireLockOnlyAtBootTime(&mVariableServicesLock);
|
|
|
|
//
|
|
// Init the communicate buffer. The buffer data size is:
|
|
// SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + sizeof (SMM_VARIABLE_COMMUNICATE_GET_PAYLOAD_SIZE);
|
|
//
|
|
CommSize = SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + sizeof (SMM_VARIABLE_COMMUNICATE_GET_PAYLOAD_SIZE);
|
|
CommBuffer = AllocateZeroPool (CommSize);
|
|
if (CommBuffer == NULL) {
|
|
Status = EFI_OUT_OF_RESOURCES;
|
|
goto Done;
|
|
}
|
|
|
|
SmmCommunicateHeader = (EFI_SMM_COMMUNICATE_HEADER *) CommBuffer;
|
|
CopyGuid (&SmmCommunicateHeader->HeaderGuid, &gEfiSmmVariableProtocolGuid);
|
|
SmmCommunicateHeader->MessageLength = SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + sizeof (SMM_VARIABLE_COMMUNICATE_GET_PAYLOAD_SIZE);
|
|
|
|
SmmVariableFunctionHeader = (SMM_VARIABLE_COMMUNICATE_HEADER *) SmmCommunicateHeader->Data;
|
|
SmmVariableFunctionHeader->Function = SMM_VARIABLE_FUNCTION_GET_PAYLOAD_SIZE;
|
|
SmmGetPayloadSize = (SMM_VARIABLE_COMMUNICATE_GET_PAYLOAD_SIZE *) SmmVariableFunctionHeader->Data;
|
|
|
|
//
|
|
// Send data to SMM.
|
|
//
|
|
Status = mSmmCommunication->Communicate (mSmmCommunication, CommBuffer, &CommSize);
|
|
ASSERT_EFI_ERROR (Status);
|
|
|
|
Status = SmmVariableFunctionHeader->ReturnStatus;
|
|
if (EFI_ERROR (Status)) {
|
|
goto Done;
|
|
}
|
|
|
|
//
|
|
// Get data from SMM.
|
|
//
|
|
*VariablePayloadSize = SmmGetPayloadSize->VariablePayloadSize;
|
|
|
|
Done:
|
|
if (CommBuffer != NULL) {
|
|
FreePool (CommBuffer);
|
|
}
|
|
ReleaseLockOnlyAtBootTime (&mVariableServicesLock);
|
|
return Status;
|
|
}
|
|
|
|
/**
|
|
This code gets information needed from SMM for runtime cache initialization.
|
|
|
|
@param[out] TotalHobStorageSize Output pointer for the total HOB storage size in bytes.
|
|
@param[out] TotalNvStorageSize Output pointer for the total non-volatile storage size in bytes.
|
|
@param[out] TotalVolatileStorageSize Output pointer for the total volatile storage size in bytes.
|
|
@param[out] AuthenticatedVariableUsage Output pointer that indicates if authenticated variables are to be used.
|
|
|
|
@retval EFI_SUCCESS Retrieved the size successfully.
|
|
@retval EFI_INVALID_PARAMETER TotalNvStorageSize parameter is NULL.
|
|
@retval EFI_OUT_OF_RESOURCES The memory resources needed for a CommBuffer are not available.
|
|
@retval Others Could not retrieve the size successfully.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
GetRuntimeCacheInfo (
|
|
OUT UINTN *TotalHobStorageSize,
|
|
OUT UINTN *TotalNvStorageSize,
|
|
OUT UINTN *TotalVolatileStorageSize,
|
|
OUT BOOLEAN *AuthenticatedVariableUsage
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
SMM_VARIABLE_COMMUNICATE_GET_RUNTIME_CACHE_INFO *SmmGetRuntimeCacheInfo;
|
|
EFI_SMM_COMMUNICATE_HEADER *SmmCommunicateHeader;
|
|
SMM_VARIABLE_COMMUNICATE_HEADER *SmmVariableFunctionHeader;
|
|
UINTN CommSize;
|
|
UINT8 *CommBuffer;
|
|
|
|
SmmGetRuntimeCacheInfo = NULL;
|
|
CommBuffer = mVariableBuffer;
|
|
|
|
if (TotalHobStorageSize == NULL || TotalNvStorageSize == NULL || TotalVolatileStorageSize == NULL || AuthenticatedVariableUsage == NULL) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
if (CommBuffer == NULL) {
|
|
return EFI_OUT_OF_RESOURCES;
|
|
}
|
|
|
|
AcquireLockOnlyAtBootTime (&mVariableServicesLock);
|
|
|
|
CommSize = SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + sizeof (SMM_VARIABLE_COMMUNICATE_GET_RUNTIME_CACHE_INFO);
|
|
ZeroMem (CommBuffer, CommSize);
|
|
|
|
SmmCommunicateHeader = (EFI_SMM_COMMUNICATE_HEADER *) CommBuffer;
|
|
CopyGuid (&SmmCommunicateHeader->HeaderGuid, &gEfiSmmVariableProtocolGuid);
|
|
SmmCommunicateHeader->MessageLength = SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + sizeof (SMM_VARIABLE_COMMUNICATE_GET_RUNTIME_CACHE_INFO);
|
|
|
|
SmmVariableFunctionHeader = (SMM_VARIABLE_COMMUNICATE_HEADER *) SmmCommunicateHeader->Data;
|
|
SmmVariableFunctionHeader->Function = SMM_VARIABLE_FUNCTION_GET_RUNTIME_CACHE_INFO;
|
|
SmmGetRuntimeCacheInfo = (SMM_VARIABLE_COMMUNICATE_GET_RUNTIME_CACHE_INFO *) SmmVariableFunctionHeader->Data;
|
|
|
|
//
|
|
// Send data to SMM.
|
|
//
|
|
Status = mSmmCommunication->Communicate (mSmmCommunication, CommBuffer, &CommSize);
|
|
ASSERT_EFI_ERROR (Status);
|
|
if (CommSize <= SMM_VARIABLE_COMMUNICATE_HEADER_SIZE) {
|
|
Status = EFI_BAD_BUFFER_SIZE;
|
|
goto Done;
|
|
}
|
|
|
|
Status = SmmVariableFunctionHeader->ReturnStatus;
|
|
if (EFI_ERROR (Status)) {
|
|
goto Done;
|
|
}
|
|
|
|
//
|
|
// Get data from SMM.
|
|
//
|
|
*TotalHobStorageSize = SmmGetRuntimeCacheInfo->TotalHobStorageSize;
|
|
*TotalNvStorageSize = SmmGetRuntimeCacheInfo->TotalNvStorageSize;
|
|
*TotalVolatileStorageSize = SmmGetRuntimeCacheInfo->TotalVolatileStorageSize;
|
|
*AuthenticatedVariableUsage = SmmGetRuntimeCacheInfo->AuthenticatedVariableUsage;
|
|
|
|
Done:
|
|
ReleaseLockOnlyAtBootTime (&mVariableServicesLock);
|
|
return Status;
|
|
}
|
|
|
|
/**
|
|
Sends the runtime variable cache context information to SMM.
|
|
|
|
@retval EFI_SUCCESS Retrieved the size successfully.
|
|
@retval EFI_INVALID_PARAMETER TotalNvStorageSize parameter is NULL.
|
|
@retval EFI_OUT_OF_RESOURCES The memory resources needed for a CommBuffer are not available.
|
|
@retval Others Could not retrieve the size successfully.;
|
|
|
|
**/
|
|
EFI_STATUS
|
|
SendRuntimeVariableCacheContextToSmm (
|
|
VOID
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
SMM_VARIABLE_COMMUNICATE_RUNTIME_VARIABLE_CACHE_CONTEXT *SmmRuntimeVarCacheContext;
|
|
EFI_SMM_COMMUNICATE_HEADER *SmmCommunicateHeader;
|
|
SMM_VARIABLE_COMMUNICATE_HEADER *SmmVariableFunctionHeader;
|
|
UINTN CommSize;
|
|
UINT8 *CommBuffer;
|
|
|
|
SmmRuntimeVarCacheContext = NULL;
|
|
CommBuffer = mVariableBuffer;
|
|
|
|
if (CommBuffer == NULL) {
|
|
return EFI_OUT_OF_RESOURCES;
|
|
}
|
|
|
|
AcquireLockOnlyAtBootTime (&mVariableServicesLock);
|
|
|
|
//
|
|
// Init the communicate buffer. The buffer data size is:
|
|
// SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + sizeof (SMM_VARIABLE_COMMUNICATE_RUNTIME_VARIABLE_CACHE_CONTEXT);
|
|
//
|
|
CommSize = SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + sizeof (SMM_VARIABLE_COMMUNICATE_RUNTIME_VARIABLE_CACHE_CONTEXT);
|
|
ZeroMem (CommBuffer, CommSize);
|
|
|
|
SmmCommunicateHeader = (EFI_SMM_COMMUNICATE_HEADER *) CommBuffer;
|
|
CopyGuid (&SmmCommunicateHeader->HeaderGuid, &gEfiSmmVariableProtocolGuid);
|
|
SmmCommunicateHeader->MessageLength = SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + sizeof (SMM_VARIABLE_COMMUNICATE_RUNTIME_VARIABLE_CACHE_CONTEXT);
|
|
|
|
SmmVariableFunctionHeader = (SMM_VARIABLE_COMMUNICATE_HEADER *) SmmCommunicateHeader->Data;
|
|
SmmVariableFunctionHeader->Function = SMM_VARIABLE_FUNCTION_INIT_RUNTIME_VARIABLE_CACHE_CONTEXT;
|
|
SmmRuntimeVarCacheContext = (SMM_VARIABLE_COMMUNICATE_RUNTIME_VARIABLE_CACHE_CONTEXT *) SmmVariableFunctionHeader->Data;
|
|
|
|
SmmRuntimeVarCacheContext->RuntimeHobCache = mVariableRuntimeHobCacheBuffer;
|
|
SmmRuntimeVarCacheContext->RuntimeVolatileCache = mVariableRuntimeVolatileCacheBuffer;
|
|
SmmRuntimeVarCacheContext->RuntimeNvCache = mVariableRuntimeNvCacheBuffer;
|
|
SmmRuntimeVarCacheContext->PendingUpdate = &mVariableRuntimeCachePendingUpdate;
|
|
SmmRuntimeVarCacheContext->ReadLock = &mVariableRuntimeCacheReadLock;
|
|
SmmRuntimeVarCacheContext->HobFlushComplete = &mHobFlushComplete;
|
|
|
|
//
|
|
// Send data to SMM.
|
|
//
|
|
Status = mSmmCommunication->Communicate (mSmmCommunication, CommBuffer, &CommSize);
|
|
ASSERT_EFI_ERROR (Status);
|
|
if (CommSize <= SMM_VARIABLE_COMMUNICATE_HEADER_SIZE) {
|
|
Status = EFI_BAD_BUFFER_SIZE;
|
|
goto Done;
|
|
}
|
|
|
|
Status = SmmVariableFunctionHeader->ReturnStatus;
|
|
if (EFI_ERROR (Status)) {
|
|
goto Done;
|
|
}
|
|
|
|
Done:
|
|
ReleaseLockOnlyAtBootTime (&mVariableServicesLock);
|
|
return Status;
|
|
}
|
|
|
|
/**
|
|
Initialize variable service and install Variable Architectural protocol.
|
|
|
|
@param[in] Event Event whose notification function is being invoked.
|
|
@param[in] Context Pointer to the notification function's context.
|
|
|
|
**/
|
|
VOID
|
|
EFIAPI
|
|
SmmVariableReady (
|
|
IN EFI_EVENT Event,
|
|
IN VOID *Context
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
|
|
Status = gBS->LocateProtocol (&gEfiSmmVariableProtocolGuid, NULL, (VOID **) &mSmmVariable);
|
|
if (EFI_ERROR (Status)) {
|
|
return;
|
|
}
|
|
|
|
Status = gBS->LocateProtocol (&gEfiSmmCommunicationProtocolGuid, NULL, (VOID **) &mSmmCommunication);
|
|
ASSERT_EFI_ERROR (Status);
|
|
|
|
//
|
|
// Allocate memory for variable communicate buffer.
|
|
//
|
|
Status = GetVariablePayloadSize (&mVariableBufferPayloadSize);
|
|
ASSERT_EFI_ERROR (Status);
|
|
mVariableBufferSize = SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + mVariableBufferPayloadSize;
|
|
mVariableBuffer = AllocateRuntimePool (mVariableBufferSize);
|
|
ASSERT (mVariableBuffer != NULL);
|
|
|
|
//
|
|
// Save the buffer physical address used for SMM conmunication.
|
|
//
|
|
mVariableBufferPhysical = mVariableBuffer;
|
|
|
|
if (FeaturePcdGet (PcdEnableVariableRuntimeCache)) {
|
|
DEBUG ((DEBUG_INFO, "Variable driver runtime cache is enabled.\n"));
|
|
//
|
|
// Allocate runtime variable cache memory buffers.
|
|
//
|
|
Status = GetRuntimeCacheInfo (
|
|
&mVariableRuntimeHobCacheBufferSize,
|
|
&mVariableRuntimeNvCacheBufferSize,
|
|
&mVariableRuntimeVolatileCacheBufferSize,
|
|
&mVariableAuthFormat
|
|
);
|
|
if (!EFI_ERROR (Status)) {
|
|
Status = InitVariableCache (&mVariableRuntimeHobCacheBuffer, &mVariableRuntimeHobCacheBufferSize);
|
|
if (!EFI_ERROR (Status)) {
|
|
Status = InitVariableCache (&mVariableRuntimeNvCacheBuffer, &mVariableRuntimeNvCacheBufferSize);
|
|
if (!EFI_ERROR (Status)) {
|
|
Status = InitVariableCache (&mVariableRuntimeVolatileCacheBuffer, &mVariableRuntimeVolatileCacheBufferSize);
|
|
if (!EFI_ERROR (Status)) {
|
|
Status = SendRuntimeVariableCacheContextToSmm ();
|
|
if (!EFI_ERROR (Status)) {
|
|
SyncRuntimeCache ();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (EFI_ERROR (Status)) {
|
|
mVariableRuntimeHobCacheBuffer = NULL;
|
|
mVariableRuntimeNvCacheBuffer = NULL;
|
|
mVariableRuntimeVolatileCacheBuffer = NULL;
|
|
}
|
|
}
|
|
ASSERT_EFI_ERROR (Status);
|
|
} else {
|
|
DEBUG ((DEBUG_INFO, "Variable driver runtime cache is disabled.\n"));
|
|
}
|
|
|
|
gRT->GetVariable = RuntimeServiceGetVariable;
|
|
gRT->GetNextVariableName = RuntimeServiceGetNextVariableName;
|
|
gRT->SetVariable = RuntimeServiceSetVariable;
|
|
gRT->QueryVariableInfo = RuntimeServiceQueryVariableInfo;
|
|
|
|
//
|
|
// Install the Variable Architectural Protocol on a new handle.
|
|
//
|
|
Status = gBS->InstallProtocolInterface (
|
|
&mHandle,
|
|
&gEfiVariableArchProtocolGuid,
|
|
EFI_NATIVE_INTERFACE,
|
|
NULL
|
|
);
|
|
ASSERT_EFI_ERROR (Status);
|
|
|
|
mVariableLock.RequestToLock = VariableLockRequestToLock;
|
|
Status = gBS->InstallMultipleProtocolInterfaces (
|
|
&mHandle,
|
|
&gEdkiiVariableLockProtocolGuid,
|
|
&mVariableLock,
|
|
NULL
|
|
);
|
|
ASSERT_EFI_ERROR (Status);
|
|
|
|
mVarCheck.RegisterSetVariableCheckHandler = VarCheckRegisterSetVariableCheckHandler;
|
|
mVarCheck.VariablePropertySet = VarCheckVariablePropertySet;
|
|
mVarCheck.VariablePropertyGet = VarCheckVariablePropertyGet;
|
|
Status = gBS->InstallMultipleProtocolInterfaces (
|
|
&mHandle,
|
|
&gEdkiiVarCheckProtocolGuid,
|
|
&mVarCheck,
|
|
NULL
|
|
);
|
|
ASSERT_EFI_ERROR (Status);
|
|
|
|
gBS->CloseEvent (Event);
|
|
}
|
|
|
|
|
|
/**
|
|
SMM Non-Volatile variable write service is ready notify event handler.
|
|
|
|
@param[in] Event Event whose notification function is being invoked.
|
|
@param[in] Context Pointer to the notification function's context.
|
|
|
|
**/
|
|
VOID
|
|
EFIAPI
|
|
SmmVariableWriteReady (
|
|
IN EFI_EVENT Event,
|
|
IN VOID *Context
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
VOID *ProtocolOps;
|
|
|
|
//
|
|
// Check whether the protocol is installed or not.
|
|
//
|
|
Status = gBS->LocateProtocol (&gSmmVariableWriteGuid, NULL, (VOID **) &ProtocolOps);
|
|
if (EFI_ERROR (Status)) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
// Some Secure Boot Policy Var (SecureBoot, etc) updates following other
|
|
// Secure Boot Policy Variable change. Record their initial value.
|
|
//
|
|
RecordSecureBootPolicyVarData();
|
|
|
|
Status = gBS->InstallProtocolInterface (
|
|
&mHandle,
|
|
&gEfiVariableWriteArchProtocolGuid,
|
|
EFI_NATIVE_INTERFACE,
|
|
NULL
|
|
);
|
|
ASSERT_EFI_ERROR (Status);
|
|
|
|
gBS->CloseEvent (Event);
|
|
}
|
|
|
|
|
|
/**
|
|
Variable Driver main entry point. The Variable driver places the 4 EFI
|
|
runtime services in the EFI System Table and installs arch protocols
|
|
for variable read and write services being available. It also registers
|
|
a notification function for an EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE event.
|
|
|
|
@param[in] ImageHandle The firmware allocated handle for the EFI image.
|
|
@param[in] SystemTable A pointer to the EFI System Table.
|
|
|
|
@retval EFI_SUCCESS Variable service successfully initialized.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
VariableSmmRuntimeInitialize (
|
|
IN EFI_HANDLE ImageHandle,
|
|
IN EFI_SYSTEM_TABLE *SystemTable
|
|
)
|
|
{
|
|
VOID *SmmVariableRegistration;
|
|
VOID *SmmVariableWriteRegistration;
|
|
EFI_EVENT OnReadyToBootEvent;
|
|
EFI_EVENT ExitBootServiceEvent;
|
|
EFI_EVENT LegacyBootEvent;
|
|
|
|
EfiInitializeLock (&mVariableServicesLock, TPL_NOTIFY);
|
|
|
|
//
|
|
// Smm variable service is ready
|
|
//
|
|
EfiCreateProtocolNotifyEvent (
|
|
&gEfiSmmVariableProtocolGuid,
|
|
TPL_CALLBACK,
|
|
SmmVariableReady,
|
|
NULL,
|
|
&SmmVariableRegistration
|
|
);
|
|
|
|
//
|
|
// Smm Non-Volatile variable write service is ready
|
|
//
|
|
EfiCreateProtocolNotifyEvent (
|
|
&gSmmVariableWriteGuid,
|
|
TPL_CALLBACK,
|
|
SmmVariableWriteReady,
|
|
NULL,
|
|
&SmmVariableWriteRegistration
|
|
);
|
|
|
|
//
|
|
// Register the event to reclaim variable for OS usage.
|
|
//
|
|
EfiCreateEventReadyToBootEx (
|
|
TPL_NOTIFY,
|
|
OnReadyToBoot,
|
|
NULL,
|
|
&OnReadyToBootEvent
|
|
);
|
|
|
|
//
|
|
// Register the event to inform SMM variable that it is at runtime.
|
|
//
|
|
gBS->CreateEventEx (
|
|
EVT_NOTIFY_SIGNAL,
|
|
TPL_NOTIFY,
|
|
OnExitBootServices,
|
|
NULL,
|
|
&gEfiEventExitBootServicesGuid,
|
|
&ExitBootServiceEvent
|
|
);
|
|
|
|
//
|
|
// Register the event to inform SMM variable that it is at runtime for legacy boot.
|
|
// Reuse OnExitBootServices() here.
|
|
//
|
|
EfiCreateEventLegacyBootEx(
|
|
TPL_NOTIFY,
|
|
OnExitBootServices,
|
|
NULL,
|
|
&LegacyBootEvent
|
|
);
|
|
|
|
//
|
|
// Register the event to convert the pointer for runtime.
|
|
//
|
|
gBS->CreateEventEx (
|
|
EVT_NOTIFY_SIGNAL,
|
|
TPL_NOTIFY,
|
|
VariableAddressChangeEvent,
|
|
NULL,
|
|
&gEfiEventVirtualAddressChangeGuid,
|
|
&mVirtualAddressChangeEvent
|
|
);
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|