MdeModulePkg/VariableRuntimeDxe: factor out boot service accesses

In preparation of providing a standalone MM based variable runtime
driver, move the existing SMM driver to the new MM services table,
and factor out some pieces that are specific to the traditional
driver, mainly related to the use of UEFI boot services, which are
not accessible to standalone MM drivers.

Contributed-under: TianoCore Contribution Agreement 1.1
Signed-off-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
Regression-tested-by: Laszlo Ersek <lersek@redhat.com>
Reviewed-by: Jian J Wang <jian.j.wang@intel.com>
Reviewed-by: Star Zeng <star.zeng@intel.com>
This commit is contained in:
Ard Biesheuvel 2019-01-03 19:28:24 +01:00
parent d0def00d33
commit a855f63e2f
5 changed files with 222 additions and 56 deletions

View File

@ -97,4 +97,67 @@ VariableSpeculationBarrier (
VOID VOID
); );
/**
Notify the system that the SMM variable driver is ready
**/
VOID
VariableNotifySmmReady (
VOID
);
/**
Notify the system that the SMM variable write driver is ready
**/
VOID
VariableNotifySmmWriteReady (
VOID
);
/**
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.
@retval EFI_SUCCESS Variable service successfully initialized.
**/
EFI_STATUS
EFIAPI
MmVariableServiceInitialize (
VOID
);
/**
This function checks if the buffer is valid per processor architecture and
does not overlap with SMRAM.
@param Buffer The buffer start address to be checked.
@param Length The buffer length to be checked.
@retval TRUE This buffer is valid per processor architecture and does not
overlap with SMRAM.
@retval FALSE This buffer is not valid per processor architecture or overlaps
with SMRAM.
**/
BOOLEAN
VariableSmmIsBufferOutsideSmmValid (
IN EFI_PHYSICAL_ADDRESS Buffer,
IN UINT64 Length
);
/**
Whether the TCG or TCG2 protocols are installed in the UEFI protocol database.
This information is used by the MorLock code to infer whether an existing
MOR variable is legitimate or not.
@retval TRUE Either the TCG or TCG2 protocol is installed in the UEFI
protocol database
@retval FALSE Neither the TCG nor the TCG2 protocol is installed in the UEFI
protocol database
**/
BOOLEAN
VariableHaveTcgProtocols (
VOID
);
#endif #endif

View File

@ -21,7 +21,6 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
#include <Library/DebugLib.h> #include <Library/DebugLib.h>
#include <Library/BaseLib.h> #include <Library/BaseLib.h>
#include <Library/BaseMemoryLib.h> #include <Library/BaseMemoryLib.h>
#include <Library/UefiBootServicesTableLib.h>
#include "Variable.h" #include "Variable.h"
typedef struct { typedef struct {
@ -419,8 +418,6 @@ MorLockInitAtEndOfDxe (
{ {
UINTN MorSize; UINTN MorSize;
EFI_STATUS MorStatus; EFI_STATUS MorStatus;
EFI_STATUS TcgStatus;
VOID *TcgInterface;
if (!mMorLockInitializationRequired) { if (!mMorLockInitializationRequired) {
// //
@ -458,20 +455,7 @@ MorLockInitAtEndOfDxe (
// can be deduced from the absence of the TCG / TCG2 protocols, as edk2's // can be deduced from the absence of the TCG / TCG2 protocols, as edk2's
// MOR implementation depends on (one of) those protocols. // MOR implementation depends on (one of) those protocols.
// //
TcgStatus = gBS->LocateProtocol ( if (VariableHaveTcgProtocols ()) {
&gEfiTcg2ProtocolGuid,
NULL, // Registration
&TcgInterface
);
if (EFI_ERROR (TcgStatus)) {
TcgStatus = gBS->LocateProtocol (
&gEfiTcgProtocolGuid,
NULL, // Registration
&TcgInterface
);
}
if (!EFI_ERROR (TcgStatus)) {
// //
// The MOR variable originates from the platform firmware; set the MOR // The MOR variable originates from the platform firmware; set the MOR
// Control Lock variable to report the locking capability to the OS. // Control Lock variable to report the locking capability to the OS.

View File

@ -15,6 +15,7 @@
SmmVariableGetStatistics() should also do validation based on its own knowledge. SmmVariableGetStatistics() should also do validation based on its own knowledge.
Copyright (c) 2010 - 2016, Intel Corporation. All rights reserved.<BR> Copyright (c) 2010 - 2016, Intel Corporation. All rights reserved.<BR>
Copyright (c) 2018, Linaro, Ltd. All rights reserved.<BR>
This program and the accompanying materials This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License are licensed and made available under the terms and conditions of the BSD License
which accompanies this distribution. The full text of the license may be found at which accompanies this distribution. The full text of the license may be found at
@ -28,18 +29,15 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
#include <Protocol/SmmVariable.h> #include <Protocol/SmmVariable.h>
#include <Protocol/SmmFirmwareVolumeBlock.h> #include <Protocol/SmmFirmwareVolumeBlock.h>
#include <Protocol/SmmFaultTolerantWrite.h> #include <Protocol/SmmFaultTolerantWrite.h>
#include <Protocol/SmmEndOfDxe.h> #include <Protocol/MmEndOfDxe.h>
#include <Protocol/SmmVarCheck.h> #include <Protocol/SmmVarCheck.h>
#include <Library/SmmServicesTableLib.h> #include <Library/MmServicesTableLib.h>
#include <Library/SmmMemLib.h>
#include <Guid/SmmVariableCommon.h> #include <Guid/SmmVariableCommon.h>
#include "Variable.h" #include "Variable.h"
extern VARIABLE_INFO_ENTRY *gVariableInfo; extern VARIABLE_INFO_ENTRY *gVariableInfo;
EFI_HANDLE mSmmVariableHandle = NULL;
EFI_HANDLE mVariableHandle = NULL;
BOOLEAN mAtRuntime = FALSE; BOOLEAN mAtRuntime = FALSE;
UINT8 *mVariableBufferPayload = NULL; UINT8 *mVariableBufferPayload = NULL;
UINTN mVariableBufferPayloadSize; UINTN mVariableBufferPayloadSize;
@ -218,7 +216,7 @@ GetFtwProtocol (
// //
// Locate Smm Fault Tolerent Write protocol // Locate Smm Fault Tolerent Write protocol
// //
Status = gSmst->SmmLocateProtocol ( Status = gMmst->MmLocateProtocol (
&gEfiSmmFaultTolerantWriteProtocolGuid, &gEfiSmmFaultTolerantWriteProtocolGuid,
NULL, NULL,
FtwProtocol FtwProtocol
@ -248,7 +246,7 @@ GetFvbByHandle (
// //
// To get the SMM FVB protocol interface on the handle // To get the SMM FVB protocol interface on the handle
// //
return gSmst->SmmHandleProtocol ( return gMmst->MmHandleProtocol (
FvBlockHandle, FvBlockHandle,
&gEfiSmmFirmwareVolumeBlockProtocolGuid, &gEfiSmmFirmwareVolumeBlockProtocolGuid,
(VOID **) FvBlock (VOID **) FvBlock
@ -287,7 +285,7 @@ GetFvbCountAndBuffer (
BufferSize = 0; BufferSize = 0;
*NumberHandles = 0; *NumberHandles = 0;
*Buffer = NULL; *Buffer = NULL;
Status = gSmst->SmmLocateHandle ( Status = gMmst->MmLocateHandle (
ByProtocol, ByProtocol,
&gEfiSmmFirmwareVolumeBlockProtocolGuid, &gEfiSmmFirmwareVolumeBlockProtocolGuid,
NULL, NULL,
@ -303,7 +301,7 @@ GetFvbCountAndBuffer (
return EFI_OUT_OF_RESOURCES; return EFI_OUT_OF_RESOURCES;
} }
Status = gSmst->SmmLocateHandle ( Status = gMmst->MmLocateHandle (
ByProtocol, ByProtocol,
&gEfiSmmFirmwareVolumeBlockProtocolGuid, &gEfiSmmFirmwareVolumeBlockProtocolGuid,
NULL, NULL,
@ -500,7 +498,7 @@ SmmVariableHandler (
return EFI_SUCCESS; return EFI_SUCCESS;
} }
if (!SmmIsBufferOutsideSmmValid ((UINTN)CommBuffer, TempCommBufferSize)) { if (!VariableSmmIsBufferOutsideSmmValid ((UINTN)CommBuffer, TempCommBufferSize)) {
DEBUG ((EFI_D_ERROR, "SmmVariableHandler: SMM communication buffer in SMRAM or overflow!\n")); DEBUG ((EFI_D_ERROR, "SmmVariableHandler: SMM communication buffer in SMRAM or overflow!\n"));
return EFI_SUCCESS; return EFI_SUCCESS;
} }
@ -911,13 +909,7 @@ SmmFtwNotificationEvent (
// //
// Notify the variable wrapper driver the variable write service is ready // Notify the variable wrapper driver the variable write service is ready
// //
Status = gBS->InstallProtocolInterface ( VariableNotifySmmWriteReady ();
&mSmmVariableHandle,
&gSmmVariableWriteGuid,
EFI_NATIVE_INTERFACE,
NULL
);
ASSERT_EFI_ERROR (Status);
return EFI_SUCCESS; return EFI_SUCCESS;
} }
@ -929,17 +921,13 @@ SmmFtwNotificationEvent (
for variable read and write services being available. It also registers for variable read and write services being available. It also registers
a notification function for an EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE event. 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. @retval EFI_SUCCESS Variable service successfully initialized.
**/ **/
EFI_STATUS EFI_STATUS
EFIAPI EFIAPI
VariableServiceInitialize ( MmVariableServiceInitialize (
IN EFI_HANDLE ImageHandle, VOID
IN EFI_SYSTEM_TABLE *SystemTable
) )
{ {
EFI_STATUS Status; EFI_STATUS Status;
@ -957,7 +945,7 @@ VariableServiceInitialize (
// Install the Smm Variable Protocol on a new handle. // Install the Smm Variable Protocol on a new handle.
// //
VariableHandle = NULL; VariableHandle = NULL;
Status = gSmst->SmmInstallProtocolInterface ( Status = gMmst->MmInstallProtocolInterface (
&VariableHandle, &VariableHandle,
&gEfiSmmVariableProtocolGuid, &gEfiSmmVariableProtocolGuid,
EFI_NATIVE_INTERFACE, EFI_NATIVE_INTERFACE,
@ -965,7 +953,7 @@ VariableServiceInitialize (
); );
ASSERT_EFI_ERROR (Status); ASSERT_EFI_ERROR (Status);
Status = gSmst->SmmInstallProtocolInterface ( Status = gMmst->MmInstallProtocolInterface (
&VariableHandle, &VariableHandle,
&gEdkiiSmmVarCheckProtocolGuid, &gEdkiiSmmVarCheckProtocolGuid,
EFI_NATIVE_INTERFACE, EFI_NATIVE_INTERFACE,
@ -976,7 +964,7 @@ VariableServiceInitialize (
mVariableBufferPayloadSize = GetMaxVariableSize () + mVariableBufferPayloadSize = GetMaxVariableSize () +
OFFSET_OF (SMM_VARIABLE_COMMUNICATE_VAR_CHECK_VARIABLE_PROPERTY, Name) - GetVariableHeaderSize (); OFFSET_OF (SMM_VARIABLE_COMMUNICATE_VAR_CHECK_VARIABLE_PROPERTY, Name) - GetVariableHeaderSize ();
Status = gSmst->SmmAllocatePool ( Status = gMmst->MmAllocatePool (
EfiRuntimeServicesData, EfiRuntimeServicesData,
mVariableBufferPayloadSize, mVariableBufferPayloadSize,
(VOID **)&mVariableBufferPayload (VOID **)&mVariableBufferPayload
@ -987,25 +975,19 @@ VariableServiceInitialize (
/// Register SMM variable SMI handler /// Register SMM variable SMI handler
/// ///
VariableHandle = NULL; VariableHandle = NULL;
Status = gSmst->SmiHandlerRegister (SmmVariableHandler, &gEfiSmmVariableProtocolGuid, &VariableHandle); Status = gMmst->MmiHandlerRegister (SmmVariableHandler, &gEfiSmmVariableProtocolGuid, &VariableHandle);
ASSERT_EFI_ERROR (Status); ASSERT_EFI_ERROR (Status);
// //
// Notify the variable wrapper driver the variable service is ready // Notify the variable wrapper driver the variable service is ready
// //
Status = SystemTable->BootServices->InstallProtocolInterface ( VariableNotifySmmReady ();
&mVariableHandle,
&gEfiSmmVariableProtocolGuid,
EFI_NATIVE_INTERFACE,
&gSmmVariable
);
ASSERT_EFI_ERROR (Status);
// //
// Register EFI_SMM_END_OF_DXE_PROTOCOL_GUID notify function. // Register EFI_SMM_END_OF_DXE_PROTOCOL_GUID notify function.
// //
Status = gSmst->SmmRegisterProtocolNotify ( Status = gMmst->MmRegisterProtocolNotify (
&gEfiSmmEndOfDxeProtocolGuid, &gEfiMmEndOfDxeProtocolGuid,
SmmEndOfDxeCallback, SmmEndOfDxeCallback,
&SmmEndOfDxeRegistration &SmmEndOfDxeRegistration
); );
@ -1014,7 +996,7 @@ VariableServiceInitialize (
// //
// Register FtwNotificationEvent () notify function. // Register FtwNotificationEvent () notify function.
// //
Status = gSmst->SmmRegisterProtocolNotify ( Status = gMmst->MmRegisterProtocolNotify (
&gEfiSmmFaultTolerantWriteProtocolGuid, &gEfiSmmFaultTolerantWriteProtocolGuid,
SmmFtwNotificationEvent, SmmFtwNotificationEvent,
&SmmFtwRegistration &SmmFtwRegistration

View File

@ -48,6 +48,7 @@
[Sources] [Sources]
Reclaim.c Reclaim.c
Variable.c Variable.c
VariableTraditionalMm.c
VariableSmm.c VariableSmm.c
VarCheck.c VarCheck.c
Variable.h Variable.h
@ -66,7 +67,7 @@
BaseLib BaseLib
SynchronizationLib SynchronizationLib
UefiLib UefiLib
SmmServicesTableLib MmServicesTableLib
BaseMemoryLib BaseMemoryLib
DebugLib DebugLib
DxeServicesTableLib DxeServicesTableLib
@ -85,7 +86,7 @@
## PRODUCES ## PRODUCES
## UNDEFINED # SmiHandlerRegister ## UNDEFINED # SmiHandlerRegister
gEfiSmmVariableProtocolGuid gEfiSmmVariableProtocolGuid
gEfiSmmEndOfDxeProtocolGuid ## NOTIFY gEfiMmEndOfDxeProtocolGuid ## NOTIFY
gEdkiiSmmVarCheckProtocolGuid ## PRODUCES gEdkiiSmmVarCheckProtocolGuid ## PRODUCES
gEfiTcgProtocolGuid ## SOMETIMES_CONSUMES gEfiTcgProtocolGuid ## SOMETIMES_CONSUMES
gEfiTcg2ProtocolGuid ## SOMETIMES_CONSUMES gEfiTcg2ProtocolGuid ## SOMETIMES_CONSUMES

View File

@ -0,0 +1,136 @@
/** @file
Parts of the SMM/MM implementation that are specific to traditional MM
Copyright (c) 2011 - 2018, Intel Corporation. All rights reserved. <BR>
Copyright (c) 2018, Linaro, Ltd. All rights reserved. <BR>
This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License
which accompanies this distribution. The full text of the license may be found at
http://opensource.org/licenses/bsd-license.php
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
**/
#include <Library/UefiBootServicesTableLib.h>
#include <Library/SmmMemLib.h>
#include "Variable.h"
/**
This function checks if the buffer is valid per processor architecture and
does not overlap with SMRAM.
@param Buffer The buffer start address to be checked.
@param Length The buffer length to be checked.
@retval TRUE This buffer is valid per processor architecture and does not
overlap with SMRAM.
@retval FALSE This buffer is not valid per processor architecture or overlaps
with SMRAM.
**/
BOOLEAN
VariableSmmIsBufferOutsideSmmValid (
IN EFI_PHYSICAL_ADDRESS Buffer,
IN UINT64 Length
)
{
return SmmIsBufferOutsideSmmValid (Buffer, Length);
}
/**
Notify the system that the SMM variable driver is ready
**/
VOID
VariableNotifySmmReady (
VOID
)
{
EFI_STATUS Status;
EFI_HANDLE Handle;
Handle = NULL;
Status = gBS->InstallProtocolInterface (
&Handle,
&gEfiSmmVariableProtocolGuid,
EFI_NATIVE_INTERFACE,
NULL
);
ASSERT_EFI_ERROR (Status);
}
/**
Notify the system that the SMM variable write driver is ready
**/
VOID
VariableNotifySmmWriteReady (
VOID
)
{
EFI_STATUS Status;
EFI_HANDLE Handle;
Handle = NULL;
Status = gBS->InstallProtocolInterface (
&Handle,
&gSmmVariableWriteGuid,
EFI_NATIVE_INTERFACE,
NULL
);
ASSERT_EFI_ERROR (Status);
}
/**
Variable service MM driver entry point
@param[in] ImageHandle A handle for the image that is initializing this
driver
@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
)
{
return MmVariableServiceInitialize ();
}
/**
Whether the TCG or TCG2 protocols are installed in the UEFI protocol database.
This information is used by the MorLock code to infer whether an existing
MOR variable is legitimate or not.
@retval TRUE Either the TCG or TCG2 protocol is installed in the UEFI
protocol database
@retval FALSE Neither the TCG nor the TCG2 protocol is installed in the UEFI
protocol database
**/
BOOLEAN
VariableHaveTcgProtocols (
VOID
)
{
EFI_STATUS Status;
VOID *Interface;
Status = gBS->LocateProtocol (
&gEfiTcg2ProtocolGuid,
NULL, // Registration
&Interface
);
if (!EFI_ERROR (Status)) {
return TRUE;
}
Status = gBS->LocateProtocol (
&gEfiTcgProtocolGuid,
NULL, // Registration
&Interface
);
return !EFI_ERROR (Status);
}