alder_lake_bios/Insyde/InsydeModulePkg/Universal/Variable/VariableRuntimeDxe/VariableRuntimeDxe.c

1069 lines
34 KiB
C

/** @file
If platform supports SMM mode, this dirver provides variable services in protected mode and SMM mode
If platform doesn't support SMM mode, this driver provides variables services in protected mode.
;******************************************************************************
;* Copyright (c) 2012 - 2021, Insyde Software Corp. All Rights Reserved.
;*
;* You may not reproduce, distribute, publish, display, perform, modify, adapt,
;* transmit, broadcast, present, recite, release, license or otherwise exploit
;* any part of this publication in any form, by any means, without the prior
;* written permission of Insyde Software Corporation.
;*
;******************************************************************************
*/
#include "Variable.h"
#include "VariableLock.h"
#include "VarCheck.h"
#include "RestoreFactoryDefault.h"
#include "Misc.h"
#include "AuthService.h"
#include "VariablePolicy.h"
#include <Protocol/NonVolatileVariable.h>
ESAL_VARIABLE_GLOBAL *mVariableModuleGlobal;
SMM_VARIABLE_INSTANCE *mSmmVariableGlobal;
EFI_SMM_SYSTEM_TABLE2 *mSmst;
VOID *mStorageArea;
VOID *mCertDbList;
EDKII_VARIABLE_LOCK_PROTOCOL mVariableLock = { VariableLockRequestToLock };
EDKII_VARIABLE_POLICY_PROTOCOL mVariablePolicyProtocol = { EDKII_VARIABLE_POLICY_PROTOCOL_REVISION,
ProtocolDisableVariablePolicy,
ProtocolIsVariablePolicyEnabled,
ProtocolRegisterVariablePolicy,
ProtocolDumpVariablePolicy,
ProtocolLockVariablePolicy };
EDKII_VAR_CHECK_PROTOCOL mVarCheck = { VarCheckRegisterSetVariableCheckHandler,
VarCheckVariablePropertySet,
VarCheckVariablePropertyGet };
EDKII_SMM_VAR_CHECK_PROTOCOL mSmmVarCheck = { VarCheckRegisterSetVariableCheckHandler,
VarCheckVariablePropertySet,
VarCheckVariablePropertyGet };
EFI_GUID *mSmmVariableDepx[] = {&gEfiSmmFtwProtocolGuid
};
/**
Calculate the number of the variable in the table.
@param[In] TablePtr pointer to the table.
@return UINTN The number of the variables in the table.
**/
UINTN
GetNumberOfVariable (
IN UINT8 *TablePtr
)
{
UINTN NumberOfVariable;
NumberOfVariable = 0;
while (!IsZeroGuid ((EFI_GUID *) TablePtr)) {
TablePtr += sizeof (EFI_GUID);
NumberOfVariable++;
TablePtr += StrSize ((CHAR16 *) TablePtr);
}
//
// Add one for the end of data
//
NumberOfVariable++;
return NumberOfVariable;
}
/**
Get the default preserved variable table from the PCD.
Adjust the structure of the table.
@param[Out] TablePtr pointer to the preserved variable table.
@retval EFI_OUT_OF_RESOURCES Allocate pool failed.
@retval EFI_SUCCESS Get the default preserved variable table successfully.
**/
EFI_STATUS
GetDefaultTable (
OUT PRESERVED_VARIABLE_TABLE **TablePtr
)
{
PRESERVED_VARIABLE_TABLE *TempTablePtr;
UINTN NumberOfVariable;
UINT8 *DefaultTablePtr;
UINTN Index;
CHAR16 *StringPtr;
StringPtr = NULL;
TempTablePtr = NULL;
DefaultTablePtr = PcdGetPtr (PcdDefaultVariableForReclaimFailTable);
if (!IsZeroGuid ((EFI_GUID *) DefaultTablePtr)) {
NumberOfVariable = GetNumberOfVariable ((UINT8 *) DefaultTablePtr);
mVariableModuleGlobal->PreservedTableSize = (UINT32) (NumberOfVariable * sizeof (PRESERVED_VARIABLE_TABLE));
TempTablePtr = VariableAllocateZeroBuffer (mVariableModuleGlobal->PreservedTableSize, TRUE);
if (TempTablePtr == NULL) {
return EFI_OUT_OF_RESOURCES;
}
//
// Adjust the table from PCD to PRESERVED_VARIABLE_TABLE.
//
for (Index = 0; (!IsZeroGuid ((EFI_GUID *) DefaultTablePtr)); Index++) {
CopyMem (&TempTablePtr[Index].VendorGuid, DefaultTablePtr, sizeof (EFI_GUID));
DefaultTablePtr += sizeof (EFI_GUID);
StringPtr = VariableAllocateZeroBuffer (StrSize ((CHAR16 *) DefaultTablePtr), TRUE);
if (StringPtr == NULL) {
return EFI_OUT_OF_RESOURCES;
}
CopyMem (StringPtr, DefaultTablePtr, StrSize ((CHAR16 *) DefaultTablePtr));
TempTablePtr[Index].VariableName = StringPtr;
//
// Go to the next variable.
//
DefaultTablePtr += StrSize (TempTablePtr[Index].VariableName);
}
}
*TablePtr = TempTablePtr;
return EFI_SUCCESS;
}
/**
Get the preserved variable table. This table will be used when the variable region is full.
**/
VOID
GetPreservedVariableTable (
VOID
)
{
EFI_STATUS Status;
PRESERVED_VARIABLE_TABLE *PreservedTablePtr;
UINTN Index;
CHAR16 *StrPtr;
StrPtr = NULL;
Status = GetDefaultTable (&PreservedTablePtr);
if (!EFI_ERROR (Status)) {
mVariableModuleGlobal->PreservedVariableTable = PreservedTablePtr;
}
DEBUG_OEM_SVC ((DEBUG_INFO, "OemKernelServices Call: OemSvcVariableForReclaimFailTable \n"));
Status = OemSvcVariableForReclaimFailTable (
&PreservedTablePtr,
&mVariableModuleGlobal->PreservedTableSize
);
DEBUG_OEM_SVC ((DEBUG_INFO, "OemKernelServices OemSvcVariableForReclaimFailTable Status: %r\n", Status));
if (!EFI_ERROR (Status)) {
return;
}
if (mVariableModuleGlobal->PreservedTableSize != 0) {
//
// Free unused table if we are using the table from the OemService.
//
if ((Status == EFI_MEDIA_CHANGED) && (mVariableModuleGlobal->PreservedVariableTable != NULL)) {
for (Index = 0; mVariableModuleGlobal->PreservedVariableTable[Index].VariableName != NULL; Index++) {
FreePool (mVariableModuleGlobal->PreservedVariableTable[Index].VariableName);
}
FreePool (mVariableModuleGlobal->PreservedVariableTable);
}
mVariableModuleGlobal->PreservedVariableTable = VariableAllocateZeroBuffer (mVariableModuleGlobal->PreservedTableSize, TRUE);
ASSERT (mVariableModuleGlobal->PreservedVariableTable != NULL);
if (mVariableModuleGlobal->PreservedVariableTable == NULL) {
return;
}
CopyMem (mVariableModuleGlobal->PreservedVariableTable, PreservedTablePtr, mVariableModuleGlobal->PreservedTableSize);
for (Index = 0; mVariableModuleGlobal->PreservedVariableTable[Index].VariableName != NULL; Index++) {
StrPtr = VariableAllocateZeroBuffer (StrSize (mVariableModuleGlobal->PreservedVariableTable[Index].VariableName), TRUE);
CopyMem (
StrPtr,
mVariableModuleGlobal->PreservedVariableTable[Index].VariableName,
StrSize (mVariableModuleGlobal->PreservedVariableTable[Index].VariableName)
);
mVariableModuleGlobal->PreservedVariableTable[Index].VariableName = StrPtr;
}
}
}
EFI_STATUS
EFIAPI
RuntimeDxeGetVariable (
IN CHAR16 *VariableName,
IN EFI_GUID * VendorGuid,
OUT UINT32 *Attributes OPTIONAL,
IN OUT UINTN *DataSize,
OUT VOID *Data
)
{
return VariableServicesGetVariable (
VariableName,
VendorGuid,
Attributes,
DataSize,
Data
);
}
EFI_STATUS
EFIAPI
RuntimeDxeGetNextVariableName (
IN OUT UINTN *VariableNameSize,
IN OUT CHAR16 *VariableName,
IN OUT EFI_GUID *VendorGuid
)
{
return VariableServicesGetNextVariableName (
VariableNameSize,
VariableName,
VendorGuid
);
}
EFI_STATUS
EFIAPI
RuntimeDxeSetVariable (
IN CHAR16 *VariableName,
IN EFI_GUID *VendorGuid,
IN UINT32 Attributes,
IN UINTN DataSize,
IN VOID *Data
)
{
return VariableServicesSetVariable (
VariableName,
VendorGuid,
Attributes,
DataSize,
Data
);
}
EFI_STATUS
EFIAPI
RuntimeDxeQueryVariableInfo (
IN UINT32 Attributes,
OUT UINT64 *MaximumVariableStorageSize,
OUT UINT64 *RemainingVariableStorageSize,
OUT UINT64 *MaximumVariableSize
)
{
return VariableServicesQueryVariableInfo (
Attributes,
MaximumVariableStorageSize,
RemainingVariableStorageSize,
MaximumVariableSize
);
}
EFI_STATUS
EFIAPI
SmmGetVariable (
IN CHAR16 *VariableName,
IN EFI_GUID * VendorGuid,
OUT UINT32 *Attributes OPTIONAL,
IN OUT UINTN *DataSize,
OUT VOID *Data
)
{
return VariableServicesGetVariable (
VariableName,
VendorGuid,
Attributes,
DataSize,
Data
);
}
EFI_STATUS
EFIAPI
SmmGetNextVariableName (
IN OUT UINTN *VariableNameSize,
IN OUT CHAR16 *VariableName,
IN OUT EFI_GUID *VendorGuid
)
{
return VariableServicesGetNextVariableName (
VariableNameSize,
VariableName,
VendorGuid
);
}
EFI_STATUS
EFIAPI
SmmSetVariable (
IN CHAR16 *VariableName,
IN EFI_GUID *VendorGuid,
IN UINT32 Attributes,
IN UINTN DataSize,
IN VOID *Data
)
{
EFI_STATUS Status;
UINT8 BackupFlashMode;
mEnableLocking = FALSE;
BackupFlashMode = *mSmmVariableGlobal->SmmFwbService->FlashMode;
*mSmmVariableGlobal->SmmFwbService->FlashMode = SMM_FW_DEFAULT_MODE;
Status = VariableServicesSetVariable (
VariableName,
VendorGuid,
Attributes,
DataSize,
Data
);
*mSmmVariableGlobal->SmmFwbService->FlashMode = BackupFlashMode;
mEnableLocking = TRUE;
return Status;
}
EFI_STATUS
EFIAPI
SmmQueryVariableInfo (
IN UINT32 Attributes,
OUT UINT64 *MaximumVariableStorageSize,
OUT UINT64 *RemainingVariableStorageSize,
OUT UINT64 *MaximumVariableSize
)
{
return VariableServicesQueryVariableInfo (
Attributes,
MaximumVariableStorageSize,
RemainingVariableStorageSize,
MaximumVariableSize
);
}
/**
Notification function of gEfiEventExitBootServicesGuid.
This is a notification function registered on gEfiEventExitBootServicesGuid 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
ExitBootServicesEvent (
IN EFI_EVENT Event,
IN VOID *Context
)
{
//
// Update AuditMode and DeployedMode variable to read-only before entring runtime.
//
UpdateAuditModeProperty (VAR_CHECK_VARIABLE_PROPERTY_READ_ONLY);
UpdateDeployedModeProperty (VAR_CHECK_VARIABLE_PROPERTY_READ_ONLY);
mVariableModuleGlobal->AtRuntime = TRUE;
gBS->CloseEvent (Event);
}
/**
Initialize SMM mode NV data
@param[in] SmmBase Pointer to EFI_SMM_BASE2_PROTOCOL
@retval EFI_SUCCESS Initialize SMM mode NV data successful.
@retval Other Any error occurred during initialize SMM NV data.
**/
EFI_STATUS
EFIAPI
SmmNvsInitialize (
IN EFI_SMM_BASE2_PROTOCOL *SmmBase
)
{
EFI_STATUS Status;
Status = SmmRamInfoInitialize ();
if (Status != EFI_SUCCESS) {
return Status;
}
mSmmVariableGlobal->Signature = SMM_VARIABLE_SIGNATURE;
Status = gBS->LocateProtocol (
&gEfiNonVolatileVariableProtocolGuid,
NULL,
(VOID **)&mSmmVariableGlobal->ProtectedModeVariableModuleGlobal
);
if (EFI_ERROR (Status)) {
return Status;
}
mSmmVariableGlobal->ProtectedModeVariableModuleGlobal->SmmCodeReady = TRUE;
//
// Since we use SMI to trigger secure boot callback functions, we needn't use
// protected mode callback functions.
//
mSmmVariableGlobal->ProtectedModeVariableModuleGlobal->SecureBootCallbackEnabled = FALSE;
//
// Copy whole mSmmVariableGlobal from mSmmVariableGlobal->ProtectedModeVariableModuleGlobal.
// Below is the access policy in SMM:
// 1.If the member in the ESAL_VARIABLE_GLOBAL structure is address or pointer, access the address from
// mVariableModuleGlobal directly. (Address in mSmmVariableGlobal->ProtectedModeVariableModuleGlobal will be
// converted to virtual address gEfiEventVirtualAddressChangeGuid event so SMM cannot access from here).
// 2.If the member in the ESAL_VARIABLE_GLOBAL structure is a data or offset, access the address from
// mSmmVariableGlobal->ProtectedModeVariableModuleGlobal (We need use ONE data in both SMM and runtime drivers
// to synchronize in both of SMM and runtime drivers.)
//
CopyMem (
mVariableModuleGlobal,
mSmmVariableGlobal->ProtectedModeVariableModuleGlobal,
sizeof (ESAL_VARIABLE_GLOBAL)
);
CopyMem (
mVariableReclaimInfo,
mSmmVariableGlobal->ProtectedModeVariableModuleGlobal->ReclaimInfo,
sizeof (VARIABLE_RECLAIM_INFO)
);
Status = GetVariableStoreInfo (
mVariableModuleGlobal->VariableBase.NonVolatileVariableBase,
&(mSmmVariableGlobal->VariableStoreInfo.FvbBaseAddress),
&(mSmmVariableGlobal->VariableStoreInfo.Lba),
&(mSmmVariableGlobal->VariableStoreInfo.Offset)
);
return Status;
}
/**
Callback routine to enable hook BootOrder variable mechanic.
@param[in] Event Event whose notification function is being invoked.
@param[in] Context Pointer to the notification function's context.
**/
VOID
EFIAPI
BootOrderHookEnableCallback (
IN EFI_EVENT Event,
IN VOID *Context
)
{
mVariableModuleGlobal->BootOrderVariableHook = TRUE;
return;
}
/**
Callback routine to disable hook BootOrder variable mechanic.
@param[in] Event Event whose notification function is being invoked.
@param[in] Context Pointer to the notification function's context.
**/
VOID
EFIAPI
BootOrderHookDisableCallback (
IN EFI_EVENT Event,
IN VOID *Context
)
{
mVariableModuleGlobal->BootOrderVariableHook = FALSE;
return;
}
/**
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
)
{
//
// convert relative base addresses or pointers
//
gRT->ConvertPointer (0x0, (VOID **) &mVariableModuleGlobal->VariableBase.NonVolatileVariableBase);
gRT->ConvertPointer (0x0, (VOID **) &mVariableModuleGlobal->VariableBase.VolatileVariableBase);
gRT->ConvertPointer (0x0, (VOID **) &mVariableModuleGlobal->NonVolatileVariableCache);
gRT->ConvertPointer (0x0, (VOID **) &mVariableModuleGlobal->FactoryDefaultBase);
gRT->ConvertPointer (0x0, (VOID **) &mVariableModuleGlobal->VariableDefaultBase);
gRT->ConvertPointer (0x0, (VOID **) &mVariableModuleGlobal->FactoryDefaultCache);
gRT->ConvertPointer (0x0, (VOID **) &mVariableModuleGlobal->VariableDefaultCache);
gRT->ConvertPointer (0x0, (VOID **) &mVariableModuleGlobal->HobVariableBase);
//
// Convert Fvb relative function pointers
//
gRT->ConvertPointer (0x0, (VOID **) &mVariableModuleGlobal->FvbInstance->GetBlockSize);
gRT->ConvertPointer (0x0, (VOID **) &mVariableModuleGlobal->FvbInstance->GetPhysicalAddress);
gRT->ConvertPointer (0x0, (VOID **) &mVariableModuleGlobal->FvbInstance->GetAttributes);
gRT->ConvertPointer (0x0, (VOID **) &mVariableModuleGlobal->FvbInstance->SetAttributes);
gRT->ConvertPointer (0x0, (VOID **) &mVariableModuleGlobal->FvbInstance->Read);
gRT->ConvertPointer (0x0, (VOID **) &mVariableModuleGlobal->FvbInstance->Write);
gRT->ConvertPointer (0x0, (VOID **) &mVariableModuleGlobal->FvbInstance);
gRT->ConvertPointer (0x0, (VOID **) &mVariableModuleGlobal->GlobalVariableList);
gRT->ConvertPointer (0x0, (VOID **) &mVariableModuleGlobal->SmmVarBuf);
gRT->ConvertPointer (0x0, (VOID **) &mVariableModuleGlobal->SmmCommunicationBuffer);
PreservedTableAddressChange ();
gRT->ConvertPointer (0x0, (VOID **) &mVariableModuleGlobal);
//
// convert reclaim relative pointer
//
gRT->ConvertPointer (0x0, (VOID **) &mVariableReclaimInfo->BackupBuffer);
gRT->ConvertPointer (0x0, (VOID **) &mVariableReclaimInfo->FtwLiteProtocol);
gRT->ConvertPointer (0x0, (VOID **) &mVariableReclaimInfo);
gRT->ConvertPointer (0x0, (VOID **) &mSmmCommunication);
ConvertVariableLockList ();
ConvertVariableCheckInfo ();
ConvertVariablePolicyTable ();
AuthVariableClassAddressChange ();
}
/**
Callback function for gEfiFaultTolerantWriteLiteProtocolGuid protocol.
This function will initialize write variable functionality.
@param Event Event whose notification function is being invoked.
@param Context Pointer to the notification function's context.
**/
VOID
EFIAPI
FaultTolerantWriteCallback (
IN EFI_EVENT Event,
IN VOID *Context
)
{
EFI_STATUS Status;
EFI_HANDLE NewHandle;
CRYPTO_SERVICES_PROTOCOL *CryptoServiceProtocol;
VOID *Registration;
EFI_EVENT NewEvent;
if (Event != NULL) {
gBS->CloseEvent (Event);
}
//
// Great!!! Now, this is a runtime driver.
//
Status = VariableCommonInitialize ();
ASSERT_EFI_ERROR (Status);
if (Status == EFI_UNSUPPORTED ) {
return;
}
GetPreservedVariableTable ();
InitializeSecureBootModesValue ();
gST->RuntimeServices->GetVariable = RuntimeDxeGetVariable;
gST->RuntimeServices->GetNextVariableName = RuntimeDxeGetNextVariableName;
gST->RuntimeServices->SetVariable = RuntimeDxeSetVariable;
gST->RuntimeServices->QueryVariableInfo = RuntimeDxeQueryVariableInfo;
//
// Now install the Variable Runtime Architectural Protocol on a new handle
//
NewHandle = NULL;
Status = gBS->InstallMultipleProtocolInterfaces (
&NewHandle,
&gEfiVariableWriteArchProtocolGuid,
NULL,
NULL
);
ASSERT_EFI_ERROR (Status);
Status = gBS->LocateProtocol (&gCryptoServicesProtocolGuid, NULL, (VOID **)&CryptoServiceProtocol);
if (!EFI_ERROR (Status)) {
CryptoCallback (NULL, NULL);
} else {
NewEvent = VariableCreateProtocolNotifyEvent (
&gCryptoServicesProtocolGuid,
TPL_CALLBACK,
CryptoCallback,
NULL,
&Registration
);
}
NewEvent = VariableCreateProtocolNotifyEvent (
&gBootOrderHookEnableGuid,
TPL_NOTIFY + 1,
BootOrderHookEnableCallback,
NULL,
&Registration
);
NewEvent = VariableCreateProtocolNotifyEvent (
&gBootOrderHookDisableGuid,
TPL_NOTIFY + 1,
BootOrderHookDisableCallback,
NULL,
&Registration
);
//
// Register the event to convert the pointer for runtime.
//
Status = gBS->CreateEventEx (
EVT_NOTIFY_SIGNAL,
TPL_NOTIFY,
VariableAddressChangeEvent,
NULL,
&gEfiEventVirtualAddressChangeGuid,
&NewEvent
);
ASSERT_EFI_ERROR (Status);
//
// Note!!!
// This driver is SMM and RuntimeDxe hybrid driver and UefiRuntimeLib creates ExitBootServices and
// VariableAddressChange event in constructor, so we cannot use this library to prevent from system
// calls function located in SMM RAM in protected mode when ExitBootServices event is signaled.
//
Status = gBS->CreateEventEx (
EVT_NOTIFY_SIGNAL,
TPL_CALLBACK,
ExitBootServicesEvent,
NULL,
&gEfiEventExitBootServicesGuid,
&NewEvent
);
ASSERT_EFI_ERROR (Status);
mVariableModuleGlobal->SecureBootCallbackEnabled = TRUE;
Status = gBS->InstallMultipleProtocolInterfaces (
&NewHandle,
&gEdkiiVariableLockProtocolGuid,
&mVariableLock,
&gEdkiiVariablePolicyProtocolGuid,
&mVariablePolicyProtocol,
NULL
);
Status = gBS->InstallMultipleProtocolInterfaces (
&NewHandle,
&gEdkiiVarCheckProtocolGuid,
&mVarCheck,
NULL
);
}
/**
Internal function to check all of protocols which need use by SMM variable services
are installed
@retval TRUE All of protocols need use by SMM variable services are installed.
@retval FALSE Any of protocol use by SMM variable services is installed.
**/
STATIC
BOOLEAN
SmmVariableServicesIsSchedule (
VOID
)
{
UINTN Index;
VOID *Protocol;
UINTN ProtocolCount;
EFI_STATUS Status;
ProtocolCount = sizeof (mSmmVariableDepx) / sizeof (EFI_GUID *);
for (Index = 0; Index < ProtocolCount; Index++) {
Status = mSmst->SmmLocateProtocol (mSmmVariableDepx[Index], NULL, &Protocol);
if (Status != EFI_SUCCESS) {
return FALSE;
}
}
return TRUE;
}
/**
The notification of ready to boot event is signaled in SMM.
@param[in] Protocol Points to the protocol's unique identifier.
@param[in] Interface Points to the interface instance.
@param[in] Handle The handle on which the interface was installed.
@retval EFI_SUCCESS All of SMM specific tasks are done successfully.
**/
EFI_STATUS
EFIAPI
SmmReadyToBootCallback (
IN CONST EFI_GUID *Protocol,
IN VOID *Interface,
IN EFI_HANDLE Handle
)
{
MorLockInitAtSmmReadyToBoot ();
return EFI_SUCCESS;
}
/**
Initial communication buffer header.
**/
VOID
InitCommunicationBufferHeader (
VOID
)
{
ZeroMem (mVariableModuleGlobal->SmmCommunicationBuffer, SMM_COMMUNICATE_HEADER_SIZE + sizeof (SMM_VAR_BUFFER));
CopyGuid (&mVariableModuleGlobal->SmmCommunicationBuffer->HeaderGuid, &gEfiSmmVariableProtocolGuid);
mVariableModuleGlobal->SmmCommunicationBuffer->MessageLength = SMM_COMMUNICATE_BUFFER_SIZE;
}
/**
Send the data in communicate buffer to SMM.
@retval EFI_SUCCESS Success is returned from the functin in SMM.
@return Others Failure is returned from the function in SMM.
**/
EFI_STATUS
SendCommunicateBuffer (
VOID
)
{
EFI_STATUS Status;
UINTN CommSize;
//
// Note!!! In runtime, the memory address is virtual address in protected mode but the memory address is
// physical address in SMM mode. Therefore, if we want to access FV through SMI in runtime, we must set data
// to virtual address in protected mode and then use physical address to call SMI.
//
mVariableModuleGlobal->SmmVarBuf->Status = EFI_UNSUPPORTED;
CommSize = SMM_COMMUNICATE_BUFFER_SIZE;
Status = mSmmCommunication->Communicate (mSmmCommunication, mSmmPhyCommunicationBuffer, &CommSize);
return mVariableModuleGlobal->SmmVarBuf->Status;
}
/**
The notification of gEfiSmmFtwProtocolGuid is installed.
This function will provide gEfiSmmVariableProtocolGuid protocol if
gEfiSmmFtwProtocolGuid is installed.
@param Protocol Points to the protocol's unique identifier.
@param Interface Points to the interface instance.
@param Handle The handle on which the interface was installed.
@retval EFI_SUCCESS Install gEfiSmmVariableProtocolGuid protocol successfully.
@retval EFI_OUT_OF_RESOURCES There are not enough memory for SMM variable services.
@retval EFI_NOT_READY Cannot find any of gEfiSmmFtwProtocolGuid or gEfiSmmCpuProtocolGuid.
@retval EFI_ALREADY_STARTED gEfiSmmVariableProtocolGuid has been installed.
@retval Other Other error occurred in this function.
**/
EFI_STATUS
EFIAPI
SmmVariableServicesCallback (
IN CONST EFI_GUID *Protocol,
IN VOID *Interface,
IN EFI_HANDLE Handle
)
{
EFI_STATUS Status;
EFI_SMM_BASE2_PROTOCOL *SmmBase;
EFI_SMM_VARIABLE_PROTOCOL *SmmVariable;
VOID *Registration;
EFI_HANDLE NewHandle;
CRYPTO_SERVICES_PROTOCOL *CryptoServiceProtocol;
ESAL_VARIABLE_GLOBAL *NonVolatileVariable;
EFI_HANDLE CommunicationHandle;
if (!SmmVariableServicesIsSchedule ()) {
return EFI_NOT_READY;
}
Status = mSmst->SmmLocateProtocol (
&gEfiSmmVariableProtocolGuid,
NULL,
(VOID **)&SmmVariable
);
if (Status == EFI_SUCCESS) {
return EFI_ALREADY_STARTED;
}
Status = gBS->LocateProtocol (
&gEfiSmmBase2ProtocolGuid,
NULL,
(VOID **)&SmmBase
);
if (Status != EFI_SUCCESS) {
return Status;
}
//
// Check runtime part of variable driver has been loaded to memory.
// There are some cases we needn't provide SMM variable services in
// this driver.
// (1) system want to use EmuVariable driver.
// (2) Any error occurred while loading runtime part variable driver.
//
Status = gBS->LocateProtocol (
&gEfiNonVolatileVariableProtocolGuid,
NULL,
(VOID **)&NonVolatileVariable
);
if (Status != EFI_SUCCESS) {
return Status;
}
mVariableModuleGlobal = VariableAllocateZeroBuffer (sizeof (ESAL_VARIABLE_GLOBAL), TRUE);
if (mVariableModuleGlobal == NULL) {
return EFI_OUT_OF_RESOURCES;
}
EfiInitializeLock (&mVariableModuleGlobal->VariableBase.VariableServicesLock, TPL_NOTIFY);
mSmmVariableGlobal = VariableAllocateZeroBuffer (sizeof (SMM_VARIABLE_INSTANCE), TRUE);
if (mSmmVariableGlobal == NULL) {
return EFI_OUT_OF_RESOURCES;
}
//
// Reserved MAX_VARIABLE_SIZE runtime buffer for "Append" operation in virtual mode.
//
mStorageArea = VariableAllocateZeroBuffer (APPEND_BUFF_SIZE, TRUE);
if (mStorageArea == NULL) {
return EFI_OUT_OF_RESOURCES;
}
//
// Reserved MAX_VARIABLE_SIZE runtime buffer for certificated database list (normal time based authenticated variable)
// operation in virtual mode.
//
mCertDbList = VariableAllocateZeroBuffer (MAX_VARIABLE_SIZE, TRUE);
if (mCertDbList == NULL) {
return EFI_OUT_OF_RESOURCES;
}
//
// Reserved memory to store reclaim information in SMM to prevent from allocating SM RAM to do
// reclaim.
//
mVariableReclaimInfo = VariableAllocateZeroBuffer (sizeof (VARIABLE_RECLAIM_INFO), TRUE);
if (mVariableReclaimInfo == NULL) {
Status = EFI_OUT_OF_RESOURCES;
}
//
// Start of relocated code (to avoid uninitialized variable access
// in the set and get variable functions in callbacks triggered by
// the installation of the protocol)
//
Status = SmmNvsInitialize (SmmBase);
SmmVariable = VariableAllocateZeroBuffer (sizeof (EFI_SMM_VARIABLE_PROTOCOL), TRUE);
if (SmmVariable == NULL) {
return EFI_OUT_OF_RESOURCES;
}
SmmVariable->SmmGetVariable = SmmGetVariable;
SmmVariable->SmmSetVariable = SmmSetVariable;
SmmVariable->SmmGetNextVariableName = SmmGetNextVariableName;
SmmVariable->SmmQueryVariableInfo = SmmQueryVariableInfo;
mSmmVariableGlobal->ProtectedModeVariableModuleGlobal->SmmSetVariable = VariableServicesSetVariable;
Status = mSmst->SmmLocateProtocol (
&gEfiSmmFwBlockServiceProtocolGuid,
NULL,
(VOID **)&mSmmVariableGlobal->SmmFwbService
);
Status = mSmst->SmmLocateProtocol (
&gCryptoServicesProtocolGuid,
NULL,
(VOID **)&CryptoServiceProtocol
);
if (!EFI_ERROR (Status)) {
CryptoCallback (NULL, NULL);
} else {
Status = mSmst->SmmRegisterProtocolNotify (
&gCryptoServicesProtocolGuid,
CryptoServicesInstalled,
&Registration
);
if (EFI_ERROR (Status)) {
return Status;
}
}
mSmst->SmiHandlerRegister (SecureBootHandler, &gEfiSmmVariableProtocolGuid, &CommunicationHandle);
Status = mSmst->SmmRegisterProtocolNotify (
&gEdkiiSmmReadyToBootProtocolGuid,
SmmReadyToBootCallback,
&Registration
);
ASSERT_EFI_ERROR (Status);
GetPreservedVariableTable ();
InitializeSecureBootModesValue ();
InitMorLockKey ();
//
// Since some drivers or libraries may need check gEfiSmmVariableProtocolGuid protocol to determine
// if they can send SMI to variable driver, Installs gEfiSmmVariableProtocolGuid after all of SMM
// callback functions are ready.
//
NewHandle = NULL;
Status = mSmst->SmmInstallProtocolInterface (
&NewHandle,
&gEfiSmmVariableProtocolGuid,
EFI_NATIVE_INTERFACE,
SmmVariable
);
//
// For compatible with native EDKII variable driver, install gEfiSmmVariableProtocolGuid in gBS.
//
NewHandle = NULL;
Status = gBS->InstallProtocolInterface (
&NewHandle,
&gEfiSmmVariableProtocolGuid,
EFI_NATIVE_INTERFACE,
SmmVariable
);
return Status;
}
/**
Internal function to register callback function to initialize SMM variable services.
@retval EFI_SUCCESS Register all of callback functions successfully.
@return Other Register callback function failed.
**/
STATIC
EFI_STATUS
RegisterSmmVariableServicesCallback (
VOID
)
{
UINTN Index;
VOID *Registration;
UINTN ProtocolCount;
EFI_STATUS Status;
ProtocolCount = sizeof (mSmmVariableDepx) / sizeof (EFI_GUID * );
for (Index = 0; Index < ProtocolCount; Index++) {
Status = mSmst->SmmRegisterProtocolNotify (
mSmmVariableDepx[Index],
SmmVariableServicesCallback,
&Registration
);
if (Status != EFI_SUCCESS) {
return Status;
}
}
return EFI_SUCCESS;
}
/**
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
VariableServiceInitialize (
IN EFI_HANDLE ImageHandle,
IN EFI_SYSTEM_TABLE *SystemTable
)
{
EFI_STATUS Status;
EFI_EVENT Event;
VOID *Registration;
EFI_SMM_BASE2_PROTOCOL *SmmBase;
BOOLEAN InSmm;
EFI_FTW_LITE_PROTOCOL *FtwLiteProtocol;
EFI_HANDLE Handle;
Status = gBS->LocateProtocol (
&gEfiSmmBase2ProtocolGuid,
NULL,
(VOID **)&SmmBase
);
InSmm = FALSE;
if (!EFI_ERROR (Status)) {
SmmBase->InSmm (SmmBase, &InSmm);
}
if (!InSmm) {
if (!IsRuntimeDriver (ImageHandle)) {
Status = RelocateImageToRuntimeDriver (ImageHandle);
ASSERT_EFI_ERROR (Status);
//
// We only want to load runtime services code to memory and don't load boot services code to memory,
// so just return EFI_ALREADY_STARTED if it isn't a runtime driver.
//
return EFI_ALREADY_STARTED;
}
Status = VariableReadyOnlyInitialize ();
if (Status != EFI_SUCCESS) {
return Status;
}
SystemTable->RuntimeServices->GetVariable = RuntimeDxeGetVariable;
SystemTable->RuntimeServices->GetNextVariableName = RuntimeDxeGetNextVariableName;
SystemTable->RuntimeServices->SetVariable = RuntimeDxeSetVariable;
SystemTable->RuntimeServices->QueryVariableInfo = RuntimeDxeQueryVariableInfo;
Handle = NULL;
Status = gBS->InstallMultipleProtocolInterfaces (
&Handle,
&gEfiReadOnlyVariableProtocolGuid,
NULL,
&gEfiVariableArchProtocolGuid,
NULL,
NULL
);
if (Status != EFI_SUCCESS) {
return Status;
}
Status = gBS->LocateProtocol (&gEfiFaultTolerantWriteLiteProtocolGuid, NULL, (VOID **) &FtwLiteProtocol);
if (Status == EFI_SUCCESS) {
FaultTolerantWriteCallback (NULL, NULL);
} else {
Event = VariableCreateProtocolNotifyEvent (
&gEfiFaultTolerantWriteLiteProtocolGuid,
TPL_CALLBACK,
FaultTolerantWriteCallback,
NULL,
&Registration
);
}
} else {
//
// Get Smm System Table
//
Status = SmmBase->GetSmstLocation(
SmmBase,
&mSmst
);
if (EFI_ERROR (Status)) {
return Status;
}
if (SmmVariableServicesIsSchedule ()) {
SmmVariableServicesCallback (NULL, NULL, NULL);
} else {
RegisterSmmVariableServicesCallback ();
}
}
return EFI_SUCCESS;
}