MdeModulePkg/FaultTolerantWriteDxe: factor out boot service accesses

In preparation of providing a standalone MM based FTW 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>
Reviewed-by: Jian J Wang <jian.j.wang@intel.com>
Regression-tested-by: Laszlo Ersek <lersek@redhat.com>
Reviewed-by: Star Zeng <star.zeng@intel.com>
This commit is contained in:
Ard Biesheuvel 2019-01-03 19:28:22 +01:00
parent e2f0d814c1
commit 22cedf5bbd
7 changed files with 233 additions and 48 deletions

View File

@ -31,7 +31,6 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
#include <Library/UefiDriverEntryPoint.h>
#include <Library/BaseMemoryLib.h>
#include <Library/MemoryAllocationLib.h>
#include <Library/UefiBootServicesTableLib.h>
#include <Library/ReportStatusCodeLib.h>
//
@ -766,4 +765,26 @@ WriteWorkSpaceData (
IN UINT8 *Buffer
);
/**
Internal implementation of CRC32. Depending on the execution context
(traditional SMM or DXE vs standalone MM), this function is implemented
via a call to the CalculateCrc32 () boot service, or via a library
call.
If Buffer is NULL, then ASSERT().
If Length is greater than (MAX_ADDRESS - Buffer + 1), then ASSERT().
@param[in] Buffer A pointer to the buffer on which the 32-bit CRC is
to be computed.
@param[in] Length The number of bytes in the buffer Data.
@retval Crc32 The 32-bit CRC was computed for the data buffer.
**/
UINT32
FtwCalculateCrc32 (
IN VOID *Buffer,
IN UINTN Length
);
#endif

View File

@ -51,6 +51,7 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
**/
#include <Library/UefiBootServicesTableLib.h>
#include "FaultTolerantWrite.h"
EFI_EVENT mFvbRegistration = NULL;
@ -250,3 +251,33 @@ FaultTolerantWriteInitialize (
return EFI_SUCCESS;
}
/**
Internal implementation of CRC32. Depending on the execution context
(traditional SMM or DXE vs standalone MM), this function is implemented
via a call to the CalculateCrc32 () boot service, or via a library
call.
If Buffer is NULL, then ASSERT().
If Length is greater than (MAX_ADDRESS - Buffer + 1), then ASSERT().
@param[in] Buffer A pointer to the buffer on which the 32-bit CRC is to be computed.
@param[in] Length The number of bytes in the buffer Data.
@retval Crc32 The 32-bit CRC was computed for the data buffer.
**/
UINT32
FtwCalculateCrc32 (
IN VOID *Buffer,
IN UINTN Length
)
{
EFI_STATUS Status;
UINT32 ReturnValue;
Status = gBS->CalculateCrc32 (Buffer, Length, &ReturnValue);
ASSERT_EFI_ERROR (Status);
return ReturnValue;
}

View File

@ -54,14 +54,13 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
**/
#include <PiSmm.h>
#include <Library/SmmServicesTableLib.h>
#include <Library/SmmMemLib.h>
#include <PiMm.h>
#include <Library/MmServicesTableLib.h>
#include <Library/BaseLib.h>
#include <Protocol/SmmSwapAddressRange.h>
#include "FaultTolerantWrite.h"
#include "FaultTolerantWriteSmmCommon.h"
#include <Protocol/SmmEndOfDxe.h>
#include <Protocol/MmEndOfDxe.h>
EFI_EVENT mFvbRegistration = NULL;
EFI_FTW_DEVICE *mFtwDevice = NULL;
@ -92,7 +91,7 @@ FtwGetFvbByHandle (
//
// To get the SMM FVB protocol interface on the handle
//
return gSmst->SmmHandleProtocol (
return gMmst->MmHandleProtocol (
FvBlockHandle,
&gEfiSmmFirmwareVolumeBlockProtocolGuid,
(VOID **) FvBlock
@ -119,7 +118,7 @@ FtwGetSarProtocol (
//
// Locate Smm Swap Address Range protocol
//
Status = gSmst->SmmLocateProtocol (
Status = gMmst->MmLocateProtocol (
&gEfiSmmSwapAddressRangeProtocolGuid,
NULL,
SarProtocol
@ -158,7 +157,7 @@ GetFvbCountAndBuffer (
BufferSize = 0;
*NumberHandles = 0;
*Buffer = NULL;
Status = gSmst->SmmLocateHandle (
Status = gMmst->MmLocateHandle (
ByProtocol,
&gEfiSmmFirmwareVolumeBlockProtocolGuid,
NULL,
@ -174,7 +173,7 @@ GetFvbCountAndBuffer (
return EFI_OUT_OF_RESOURCES;
}
Status = gSmst->SmmLocateHandle (
Status = gMmst->MmLocateHandle (
ByProtocol,
&gEfiSmmFirmwareVolumeBlockProtocolGuid,
NULL,
@ -336,7 +335,7 @@ SmmFaultTolerantWriteHandler (
}
CommBufferPayloadSize = TempCommBufferSize - SMM_FTW_COMMUNICATE_HEADER_SIZE;
if (!SmmIsBufferOutsideSmmValid ((UINTN)CommBuffer, TempCommBufferSize)) {
if (!FtwSmmIsBufferOutsideSmmValid ((UINTN)CommBuffer, TempCommBufferSize)) {
DEBUG ((EFI_D_ERROR, "SmmFtwHandler: SMM communication buffer in SMRAM or overflow!\n"));
return EFI_SUCCESS;
}
@ -525,13 +524,12 @@ FvbNotificationEvent (
EFI_STATUS Status;
EFI_SMM_FAULT_TOLERANT_WRITE_PROTOCOL *FtwProtocol;
EFI_HANDLE SmmFtwHandle;
EFI_HANDLE FtwHandle;
//
// Just return to avoid install SMM FaultTolerantWriteProtocol again
// if SMM Fault Tolerant Write protocol had been installed.
//
Status = gSmst->SmmLocateProtocol (
Status = gMmst->MmLocateProtocol (
&gEfiSmmFaultTolerantWriteProtocolGuid,
NULL,
(VOID **) &FtwProtocol
@ -551,7 +549,7 @@ FvbNotificationEvent (
//
// Install protocol interface
//
Status = gSmst->SmmInstallProtocolInterface (
Status = gMmst->MmInstallProtocolInterface (
&mFtwDevice->Handle,
&gEfiSmmFaultTolerantWriteProtocolGuid,
EFI_NATIVE_INTERFACE,
@ -562,20 +560,13 @@ FvbNotificationEvent (
///
/// Register SMM FTW SMI handler
///
Status = gSmst->SmiHandlerRegister (SmmFaultTolerantWriteHandler, &gEfiSmmFaultTolerantWriteProtocolGuid, &SmmFtwHandle);
Status = gMmst->MmiHandlerRegister (SmmFaultTolerantWriteHandler, &gEfiSmmFaultTolerantWriteProtocolGuid, &SmmFtwHandle);
ASSERT_EFI_ERROR (Status);
//
// Notify the Ftw wrapper driver SMM Ftw is ready
//
FtwHandle = NULL;
Status = gBS->InstallProtocolInterface (
&FtwHandle,
&gEfiSmmFaultTolerantWriteProtocolGuid,
EFI_NATIVE_INTERFACE,
NULL
);
ASSERT_EFI_ERROR (Status);
FtwNotifySmmReady ();
return EFI_SUCCESS;
}
@ -592,7 +583,7 @@ FvbNotificationEvent (
**/
EFI_STATUS
EFIAPI
SmmEndOfDxeCallback (
MmEndOfDxeCallback (
IN CONST EFI_GUID *Protocol,
IN VOID *Interface,
IN EFI_HANDLE Handle
@ -603,25 +594,19 @@ SmmEndOfDxeCallback (
}
/**
This function is the entry point of the Fault Tolerant Write driver.
@param[in] ImageHandle A handle for the image that is initializing this driver
@param[in] SystemTable A pointer to the EFI system table
Shared entry point of the module
@retval EFI_SUCCESS The initialization finished successfully.
@retval EFI_OUT_OF_RESOURCES Allocate memory error
@retval EFI_INVALID_PARAMETER Workspace or Spare block does not exist
**/
EFI_STATUS
EFIAPI
SmmFaultTolerantWriteInitialize (
IN EFI_HANDLE ImageHandle,
IN EFI_SYSTEM_TABLE *SystemTable
MmFaultTolerantWriteInitialize (
VOID
)
{
EFI_STATUS Status;
VOID *SmmEndOfDxeRegistration;
VOID *MmEndOfDxeRegistration;
//
// Allocate private data structure for SMM FTW protocol and do some initialization
@ -634,17 +619,17 @@ SmmFaultTolerantWriteInitialize (
//
// Register EFI_SMM_END_OF_DXE_PROTOCOL_GUID notify function.
//
Status = gSmst->SmmRegisterProtocolNotify (
&gEfiSmmEndOfDxeProtocolGuid,
SmmEndOfDxeCallback,
&SmmEndOfDxeRegistration
Status = gMmst->MmRegisterProtocolNotify (
&gEfiMmEndOfDxeProtocolGuid,
MmEndOfDxeCallback,
&MmEndOfDxeRegistration
);
ASSERT_EFI_ERROR (Status);
//
// Register FvbNotificationEvent () notify function.
//
Status = gSmst->SmmRegisterProtocolNotify (
Status = gMmst->MmRegisterProtocolNotify (
&gEfiSmmFirmwareVolumeBlockProtocolGuid,
FvbNotificationEvent,
&mFvbRegistration

View File

@ -37,6 +37,7 @@
FtwMisc.c
UpdateWorkingBlock.c
FaultTolerantWrite.c
FaultTolerantWriteTraditionalMm.c
FaultTolerantWriteSmm.c
FaultTolerantWrite.h
FaultTolerantWriteSmmCommon.h
@ -46,7 +47,7 @@
MdeModulePkg/MdeModulePkg.dec
[LibraryClasses]
SmmServicesTableLib
MmServicesTableLib
MemoryAllocationLib
BaseMemoryLib
UefiDriverEntryPoint
@ -73,7 +74,7 @@
## PRODUCES
## UNDEFINED # SmiHandlerRegister
gEfiSmmFaultTolerantWriteProtocolGuid
gEfiSmmEndOfDxeProtocolGuid ## CONSUMES
gEfiMmEndOfDxeProtocolGuid ## CONSUMES
[FeaturePcd]
gEfiMdeModulePkgTokenSpaceGuid.PcdFullFtwServiceEnable ## CONSUMES

View File

@ -77,4 +77,43 @@ typedef struct {
UINT8 Data[1];
} SMM_FTW_GET_LAST_WRITE_HEADER;
/**
Shared entry point of the module
@retval EFI_SUCCESS The initialization finished successfully.
@retval EFI_OUT_OF_RESOURCES Allocate memory error
@retval EFI_INVALID_PARAMETER Workspace or Spare block does not exist
**/
EFI_STATUS
MmFaultTolerantWriteInitialize (
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
FtwSmmIsBufferOutsideSmmValid (
IN EFI_PHYSICAL_ADDRESS Buffer,
IN UINT64 Length
);
/**
Notify the system that the SMM FTW driver is ready
**/
VOID
FtwNotifySmmReady (
VOID
);
#endif

View File

@ -0,0 +1,114 @@
/** @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/SmmMemLib.h>
#include <Library/UefiBootServicesTableLib.h>
#include "FaultTolerantWrite.h"
#include "FaultTolerantWriteSmmCommon.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
FtwSmmIsBufferOutsideSmmValid (
IN EFI_PHYSICAL_ADDRESS Buffer,
IN UINT64 Length
)
{
return SmmIsBufferOutsideSmmValid (Buffer, Length);
}
/**
Internal implementation of CRC32. Depending on the execution context
(traditional SMM or DXE vs standalone MM), this function is implemented
via a call to the CalculateCrc32 () boot service, or via a library
call.
If Buffer is NULL, then ASSERT().
If Length is greater than (MAX_ADDRESS - Buffer + 1), then ASSERT().
@param[in] Buffer A pointer to the buffer on which the 32-bit CRC is
to be computed.
@param[in] Length The number of bytes in the buffer Data.
@retval Crc32 The 32-bit CRC was computed for the data buffer.
**/
UINT32
FtwCalculateCrc32 (
IN VOID *Buffer,
IN UINTN Length
)
{
EFI_STATUS Status;
UINT32 ReturnValue;
Status = gBS->CalculateCrc32 (Buffer, Length, &ReturnValue);
ASSERT_EFI_ERROR (Status);
return ReturnValue;
}
/**
Notify the system that the SMM FTW driver is ready
**/
VOID
FtwNotifySmmReady (
VOID
)
{
EFI_HANDLE FtwHandle;
EFI_STATUS Status;
FtwHandle = NULL;
Status = gBS->InstallProtocolInterface (
&FtwHandle,
&gEfiSmmFaultTolerantWriteProtocolGuid,
EFI_NATIVE_INTERFACE,
NULL
);
ASSERT_EFI_ERROR (Status);
}
/**
This function is the entry point of the Fault Tolerant Write driver.
@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 The initialization finished successfully.
@retval EFI_OUT_OF_RESOURCES Allocate memory error
@retval EFI_INVALID_PARAMETER Workspace or Spare block does not exist
**/
EFI_STATUS
EFIAPI
SmmFaultTolerantWriteInitialize (
IN EFI_HANDLE ImageHandle,
IN EFI_SYSTEM_TABLE *SystemTable
)
{
return MmFaultTolerantWriteInitialize ();
}

View File

@ -29,8 +29,6 @@ InitializeLocalWorkSpaceHeader (
VOID
)
{
EFI_STATUS Status;
//
// Check signature with gEdkiiWorkingBlockSignatureGuid.
//
@ -64,12 +62,8 @@ InitializeLocalWorkSpaceHeader (
//
// Calculate the Crc of woking block header
//
Status = gBS->CalculateCrc32 (
&mWorkingBlockHeader,
sizeof (EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER),
&mWorkingBlockHeader.Crc
);
ASSERT_EFI_ERROR (Status);
mWorkingBlockHeader.Crc = FtwCalculateCrc32 (&mWorkingBlockHeader,
sizeof (EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER));
mWorkingBlockHeader.WorkingBlockValid = FTW_VALID_STATE;
mWorkingBlockHeader.WorkingBlockInvalid = FTW_INVALID_STATE;