alder_lake_bios/Insyde/InsydeModulePkg/Universal/FirmwareVolume/FwBlockServiceSmm/FwBlockServiceSmm.c

928 lines
32 KiB
C

/** @file
This driver provides Firmware block services interface in SMM 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 "FwBlockServiceSmm.h"
#include <PostCode.h>
#define EFI_SMM_FWB_READY_PROTOCOL_GUID \
{ \
0x3aeaec5f, 0x945a, 0x4ba5, 0xab, 0x98, 0xbc, 0x23, 0x4, 0x97, 0xb9, 0x8d \
}
EFI_GUID mEfiSmmFwbReadyProtocolGuid = EFI_SMM_FWB_READY_PROTOCOL_GUID;
SMM_FW_BLOCK_SERVICE_INSTANCE *mSmmFwbGlobal;
UINT8 mSmmFlashMode;
EFI_SMM_SYSTEM_TABLE2 *mSmst;
EFI_SMM_COMMUNICATION_PROTOCOL *mSmmCommunication;
UINT8 *mFwbBuffer;
UINTN mFwbBufferSize;
BOOLEAN mEfiAtRuntime = FALSE;
typedef struct {
UINT64 Id;
UINT8 Size;
CHAR8 VendorName[MAX_STRING];
CHAR8 DeviceName[MAX_STRING];
FD_BLOCK_MAP BlockMap;
} ECP_FD_INFO;
typedef struct {
FD_INFO DeviceInfo;
UINT8 *DummyPtr[6];
} ECP_FLASH_DEVICE;
/**
Creates and returns a notification event and registers that event with all the protocol
instances specified by ProtocolGuid.
This function causes the notification function to be executed for every protocol of type
ProtocolGuid instance that exists in the system when this function is invoked. In addition,
every time a protocol of type ProtocolGuid instance is installed or reinstalled, the notification
function is also executed. This function returns the notification event that was created.
If ProtocolGuid is NULL, then ASSERT().
If NotifyTpl is not a legal TPL value, then ASSERT().
If NotifyFunction is NULL, then ASSERT().
If Registration is NULL, then ASSERT().
@param[in] ProtocolGuid Supplies GUID of the protocol upon whose installation the event is fired.
@param[in] NotifyTpl Supplies the task priority level of the event notifications.
@param[in] NotifyFunction Supplies the function to notify when the event is signaled.
@param[in] NotifyContext The context parameter to pass to NotifyFunction.
@param[out] Registration A pointer to a memory location to receive the registration value.
This value is passed to LocateHandle() to obtain new handles that
have been added that support the ProtocolGuid-specified protocol.
@return The notification event that was created.
**/
EFI_EVENT
EFIAPI
SmmFwCreateProtocolNotifyEvent (
IN EFI_GUID *ProtocolGuid,
IN EFI_TPL NotifyTpl,
IN EFI_EVENT_NOTIFY NotifyFunction,
IN VOID *NotifyContext, OPTIONAL
OUT VOID **Registration
)
{
EFI_STATUS Status;
EFI_EVENT Event;
ASSERT (ProtocolGuid != NULL);
ASSERT (NotifyFunction != NULL);
ASSERT (Registration != NULL);
//
// Create the event
//
Status = gBS->CreateEvent (
EVT_NOTIFY_SIGNAL,
NotifyTpl,
NotifyFunction,
NotifyContext,
&Event
);
ASSERT_EFI_ERROR (Status);
//
// Register for protocol notifications on this event
//
Status = gBS->RegisterProtocolNotify (
ProtocolGuid,
Event,
Registration
);
ASSERT_EFI_ERROR (Status);
return Event;
}
/**
Initialize boot time SMM firmware block service and install protocol.
@param[in] Event Event whose notification function is being invoked.
@param[in] Context Pointer to the notification function's context.
**/
VOID
EFIAPI
SmmFwbReady (
IN EFI_EVENT Event,
IN VOID *Context
)
{
EFI_SMM_FW_BLOCK_SERVICE_PROTOCOL *SmmFwbService;
VOID *SmmFwbReady;
EFI_STATUS Status;
EFI_HANDLE Handle;
Status = gBS->LocateProtocol (&mEfiSmmFwbReadyProtocolGuid, NULL, (VOID **)&SmmFwbReady);
if (EFI_ERROR (Status)) {
return;
}
SmmFwbService = AllocatePool (sizeof (EFI_SMM_FW_BLOCK_SERVICE_PROTOCOL));
ASSERT (SmmFwbService != NULL);
if (SmmFwbService == NULL) {
return;
}
Status = gBS->LocateProtocol (&gEfiSmmCommunicationProtocolGuid, NULL, (VOID **) &mSmmCommunication);
ASSERT_EFI_ERROR (Status);
SmmFwbService->DetectDevice = BsFlashFdDetectDevice;
SmmFwbService->Read = BsFlashFdRead;
SmmFwbService->Write = BsFlashFdWrite;
SmmFwbService->EraseBlocks = BsFlashFdEraseBlocks;
SmmFwbService->GetFlashTable = BsFlashFdGetFlashTable;
SmmFwbService->GetSpiFlashNumber = BsFlashFdGetSpiFlashNumber;
SmmFwbService->ConvertToSpiAddress = BsFlashFdConvertToSpiAddress;
Handle = NULL;
Status = gBS->InstallProtocolInterface (
&Handle,
&gEfiSmmFwBlockServiceProtocolGuid,
EFI_NATIVE_INTERFACE,
SmmFwbService
);
}
/**
Communication service SMI Handler entry.
This SMI handler provides services for the firmware volume access through SMI.
@param[in] DispatchHandle The unique handle assigned to this handler by SmiHandlerRegister().
@param[in] RegisterContext Points to an optional handler context which was specified when the
handler was registered.
@param[in, out] CommBuffer A pointer to a collection of data in memory that will
be conveyed from a non-SMM environment into an SMM environment.
@param[in, out] CommBufferSize The size of the CommBuffer.
@retval EFI_SUCCESS The interrupt was handled and quiesced. No other handlers
should still be called.
@retval EFI_WARN_INTERRUPT_SOURCE_QUIESCED The interrupt has been quiesced but other handlers should
still be called.
@retval EFI_WARN_INTERRUPT_SOURCE_PENDING The interrupt is still pending and other handlers should still
be called.
@retval EFI_INTERRUPT_PENDING The interrupt could not be quiesced.
**/
EFI_STATUS
EFIAPI
SmmFwBlockServiceHandler (
IN EFI_HANDLE DispatchHandle,
IN CONST VOID *RegisterContext,
IN OUT VOID *CommBuffer,
IN OUT UINTN *CommBufferSize
)
{
SMM_FWB_COMMUNICATE_HEADER *SmmFwbFunctionHeader;
SMM_FWB_COMMUNICATE_ACCESS_FVB *SmmFwbAccessFvb;
SMM_FWB_COMMUNICATE_HEADER *FwbFunctionHeader;
SMM_FWB_COMMUNICATE_ACCESS_FVB *FwbAccessFvb;
EFI_STATUS Status;
if (CommBuffer == NULL || CommBufferSize == NULL || mEfiAtRuntime) {
return EFI_SUCCESS;
}
//
// Check buffer size, address, must be the memory which is allocated in DXE part entry point to make sure
// the memory will not overlap SMM RAM.
//
if (*CommBufferSize != mFwbBufferSize - SMM_COMMUNICATE_HEADER_SIZE ||
(UINTN)CommBuffer != (UINTN)mFwbBuffer + SMM_COMMUNICATE_HEADER_SIZE) {
return EFI_SUCCESS;
}
//
// Copy SMM_FWB_COMMUNICATE_HEADER and SMM_FWB_COMMUNICATE_ACCESS_FVB to SMRAM to prevent from TOCTOU attack.
//
FwbFunctionHeader = (SMM_FWB_COMMUNICATE_HEADER *)CommBuffer;
FwbAccessFvb = (SMM_FWB_COMMUNICATE_ACCESS_FVB *)FwbFunctionHeader->Data;
SmmFwbFunctionHeader = AllocateCopyPool (sizeof (SMM_FWB_COMMUNICATE_HEADER), FwbFunctionHeader);
if (SmmFwbFunctionHeader == NULL) {
return EFI_SUCCESS;
}
SmmFwbAccessFvb = AllocateCopyPool (sizeof (SMM_FWB_COMMUNICATE_ACCESS_FVB), FwbAccessFvb);
if (SmmFwbAccessFvb == NULL) {
FreePool (SmmFwbFunctionHeader);
return EFI_SUCCESS;
}
switch (SmmFwbFunctionHeader->Function) {
case SMM_FWB_FUNCTION_READ:
//
// Access data must be in CommBuffer region.
//
if (SmmFwbAccessFvb->NumBytes > BLOCK_SIZE) {
return EFI_SUCCESS;
}
Status = FlashFdRead (NULL, SmmFwbAccessFvb->Address, 0, &SmmFwbAccessFvb->NumBytes, (UINT8 *) (FwbAccessFvb + 1));
SmmFwbFunctionHeader->ReturnStatus = Status;
break;
case SMM_FWB_FUNCTION_WRITE:
//
// Access data must be in CommBuffer region.
//
if (SmmFwbAccessFvb->NumBytes > BLOCK_SIZE) {
return EFI_SUCCESS;
}
Status = FlashFdWrite (NULL, SmmFwbAccessFvb->Address, &SmmFwbAccessFvb->NumBytes, (UINT8 *) (FwbAccessFvb + 1));
SmmFwbFunctionHeader->ReturnStatus = Status;
break;
case SMM_FWB_FUNCTION_ERASE_BLOCKS:
Status = FlashFdEraseBlocks (NULL, SmmFwbAccessFvb->Address, &SmmFwbAccessFvb->NumBytes);
SmmFwbFunctionHeader->ReturnStatus = Status;
break;
default:
ASSERT (FALSE);
break;
}
//
// Restore data from SMRAM to parameter communication buffer.
//
CopyMem (FwbFunctionHeader, SmmFwbFunctionHeader, sizeof (SMM_FWB_COMMUNICATE_HEADER));
FreePool (SmmFwbFunctionHeader);
CopyMem (FwbAccessFvb, SmmFwbAccessFvb, sizeof (SMM_FWB_COMMUNICATE_ACCESS_FVB));
FreePool (SmmFwbAccessFvb);
return EFI_SUCCESS;
}
/**
Set AtRuntime flag as TRUE after ExitBootServices or LegacyBoot.
@param[in] Event useless here, but required in functions invoked by events
@param[in] Context useless here, but required in functions invoked by events
@retval None
**/
VOID
EFIAPI
SmmFwRuntimeCallback (
IN EFI_EVENT Event,
IN VOID *Context
)
{
mEfiAtRuntime = TRUE;
}
/**
The driver's entry point.
This driver provides Firmware block services interface in SMM mode.
@param[in] ImageHandle The firmware allocated handle for the EFI image.
@param[in] SystemTable A pointer to the EFI System Table.
@retval EFI_SUCCESS The entry point is executed successfully.
@retval Others Some error occurs when executing this entry point.
**/
EFI_STATUS
EFIAPI
SmmFwBlockServiceInitialize (
IN EFI_HANDLE ImageHandle,
IN EFI_SYSTEM_TABLE *SystemTable
)
{
EFI_STATUS Status;
EFI_HANDLE Handle;
EFI_EVENT Event;
EFI_SMM_BASE2_PROTOCOL *SmmBase;
BOOLEAN InSmm;
VOID *SmmFwbRegistration;
Status = gBS->LocateProtocol (
&gEfiSmmBase2ProtocolGuid,
NULL,
(VOID **)&SmmBase
);
InSmm = FALSE;
if (!EFI_ERROR (Status)) {
SmmBase->InSmm (SmmBase, &InSmm);
}
if (!InSmm) {
EfiCreateProtocolNotifyEvent (
&mEfiSmmFwbReadyProtocolGuid,
TPL_CALLBACK,
SmmFwbReady,
NULL,
&SmmFwbRegistration
);
EfiCreateEventLegacyBootEx (
TPL_CALLBACK,
SmmFwRuntimeCallback,
NULL,
&Event
);
gBS->CreateEventEx (
EVT_NOTIFY_SIGNAL,
TPL_CALLBACK,
SmmFwRuntimeCallback,
NULL,
&gEfiEventExitBootServicesGuid,
&Event
);
//
// To prevent from causing CPU exception if copper point is enabled, change to use EfiRuntimeServicesData type memory
// as SMM communication buffer.
//
mFwbBuffer = AllocateRuntimePool (SMM_FWB_COMMUNICATE_ACCESS_FVB_SIZE + BLOCK_SIZE);
ASSERT (mFwbBuffer != NULL);
if (mFwbBuffer == NULL) {
return EFI_OUT_OF_RESOURCES;
}
mFwbBufferSize = SMM_FWB_COMMUNICATE_ACCESS_FVB_SIZE + BLOCK_SIZE;
Handle = NULL;
Status = gBS->InstallMultipleProtocolInterfaces (
&Handle,
&gEfiCallerIdGuid,
mFwbBuffer,
NULL
);
return EFI_SUCCESS;
}
Status = SmmBase->GetSmstLocation(
SmmBase,
&mSmst
);
if (EFI_ERROR (Status)) {
return Status;
}
mSmmFwbGlobal = AllocatePool (sizeof (SMM_FW_BLOCK_SERVICE_INSTANCE));
if (mSmmFwbGlobal == NULL) {
return EFI_OUT_OF_RESOURCES;
}
ZeroMem (mSmmFwbGlobal, sizeof (SMM_FW_BLOCK_SERVICE_INSTANCE));
mSmmFwbGlobal->Signature = SMM_FW_BLOCK_SERVICE_SIGNATURE;
mSmmFlashMode = SMM_FW_DEFAULT_MODE;
mSmmFwbGlobal->SmmFwbService.FlashMode = &mSmmFlashMode;
mSmmFwbGlobal->SmmFwbService.DetectDevice = FlashFdDetectDevice;
mSmmFwbGlobal->SmmFwbService.Read = FlashFdRead;
mSmmFwbGlobal->SmmFwbService.Write = FlashFdWrite;
mSmmFwbGlobal->SmmFwbService.EraseBlocks = FlashFdEraseBlocks;
mSmmFwbGlobal->SmmFwbService.GetFlashTable = FlashFdGetFlashTable;
mSmmFwbGlobal->SmmFwbService.GetSpiFlashNumber = FlashFdGetSpiFlashNumber;
mSmmFwbGlobal->SmmFwbService.ConvertToSpiAddress = FlashFdConvertToSpiAddress;
Handle = NULL;
Status = mSmst->SmmInstallProtocolInterface (
&Handle,
&gEfiSmmFwBlockServiceProtocolGuid,
EFI_NATIVE_INTERFACE,
&mSmmFwbGlobal->SmmFwbService
);
InitFlashMode (mSmmFwbGlobal->SmmFwbService.FlashMode);
Handle = NULL;
Status = mSmst->SmiHandlerRegister (SmmFwBlockServiceHandler, &gEfiSmmFwBlockServiceProtocolGuid, &Handle);
Handle = NULL;
Status = gBS->InstallProtocolInterface (
&Handle,
&mEfiSmmFwbReadyProtocolGuid,
EFI_NATIVE_INTERFACE,
NULL
);
Status = gBS->LocateProtocol (
&gEfiCallerIdGuid,
NULL,
(VOID **) &mFwbBuffer
);
mFwbBufferSize = SMM_FWB_COMMUNICATE_ACCESS_FVB_SIZE + BLOCK_SIZE;
return Status;
}
/**
Detect target flash device and copy whole flash device to output buffer.
@param[in] This Pointer to EFI_SMM_FW_BLOCK_SERVICE_PROTOCOL instance.
@param[out] SystemTable Buffer to saved target flash device information
@retval EFI_SUCCESS The flash device is recognized successfully.
@retval EFI_NOT_FOUND Cannot find supported flash device.
@retval EFI_INVALID_PARAMETER Invalid function parameter.
**/
EFI_STATUS
EFIAPI
FlashFdDetectDevice (
IN EFI_SMM_FW_BLOCK_SERVICE_PROTOCOL *This,
OUT UINT8 *Buffer
)
{
EFI_STATUS Status;
if (Buffer == NULL) {
return EFI_INVALID_PARAMETER;
}
Status = GetFlashDevice (&mSmmFwbGlobal->FlashDevice);
if (EFI_ERROR (Status)) {
return Status;
}
CopyMem (Buffer, mSmmFwbGlobal->FlashDevice, sizeof (FLASH_DEVICE));
return EFI_SUCCESS;
}
/**
Detect target flash device and copy whole flash device to output buffer for ECP driver.
@param[in] This Pointer to EFI_SMM_FW_BLOCK_SERVICE_PROTOCOL instance.
@param[out] SystemTable Buffer to saved target flash device information
@retval EFI_SUCCESS The flash device is recognized successfully.
@retval EFI_NOT_FOUND Cannot find supported flash device.
@retval EFI_INVALID_PARAMETER Invalid function parameter.
**/
EFI_STATUS
EFIAPI
EcpFlashFdDetectDevice (
IN EFI_SMM_FW_BLOCK_SERVICE_PROTOCOL *This,
OUT UINT8 *Buffer
)
{
ECP_FLASH_DEVICE EcpFlashDevice;
EFI_STATUS Status;
Status = FlashFdDetectDevice (This, Buffer);
if (EFI_ERROR (Status)) {
return Status;
}
ZeroMem (&EcpFlashDevice, sizeof (ECP_FLASH_DEVICE));
CopyMem (&EcpFlashDevice.DeviceInfo, &(((FLASH_DEVICE *) Buffer)->DeviceInfo), sizeof (ECP_FD_INFO));
CopyMem (Buffer, &EcpFlashDevice, sizeof (ECP_FLASH_DEVICE));
return EFI_SUCCESS;
}
/**
Reads data beginning at Lba:Offset from FV and places the data in Buffer.
The read terminates either when *NumBytes of data have been read, or when
a block boundary is reached. *NumBytes is updated to reflect the actual
number of bytes read.
@param [in] This Pointer to EFI_SMM_FW_BLOCK_SERVICE_PROTOCOL instance.
@param [in] WriteAddress Start LBA address which want to read.
@param [in] Offset Offset in the block at which to begin read
@param [in, out] NumBytes IN: The requested read size.
OUT: The data size by bytes has been read
@param [out] Buffer Data buffer in which to place data read.
@retval EFI_SUCCESS Read data successful.
@retval EFI_INVALID_PARAMETER Input function parameters are invalid.
@retval EFI_UNSUPPORTED The flash device is not supported
@retval EFI_DEVICE_ERROR Read data failed caused by device error.
**/
EFI_STATUS
EFIAPI
FlashFdRead (
IN EFI_SMM_FW_BLOCK_SERVICE_PROTOCOL *This,
IN UINTN WriteAddress,
IN UINTN Offset,
IN OUT UINTN *NumBytes,
OUT UINT8 *Buffer
)
{
return FlashRead (Buffer, (UINT8 *) (WriteAddress + Offset), *NumBytes);
}
/**
Writes data beginning at Lba:Offset from FV. The write terminates either
when *NumBytes of data have been written, or when a block boundary is
reached. *NumBytes is updated to reflect the actual number of bytes
written.
@param [in] This Pointer to EFI_SMM_FW_BLOCK_SERVICE_PROTOCOL instance.
@param [in] Offset Start address to be written.
@param [in, out] NumBytes IN: The requested write size.
OUT: The data size by bytes has been written.
@param [out] Buffer Data buffer want to write.
@retval EFI_SUCCESS Write data successful.
@retval EFI_INVALID_PARAMETER Input function parameters are invalid.
@retval EFI_UNSUPPORTED The flash device is not supported
@retval EFI_DEVICE_ERROR Write data failed caused by device error.
**/
EFI_STATUS
EFIAPI
FlashFdWrite (
IN EFI_SMM_FW_BLOCK_SERVICE_PROTOCOL *This,
IN UINTN WriteAddress,
IN OUT UINTN *NumBytes,
IN UINT8 *Buffer
)
{
return FlashProgram ((UINT8 *) WriteAddress, Buffer, NumBytes, WriteAddress);
}
/**
The EraseBlock() function erases one or more blocks as denoted by the
variable argument list. The entire parameter list of blocks must be verified
prior to erasing any blocks. If a block is requested that does not exist
within the associated firmware volume (it has a larger index than the last
block of the firmware volume), the EraseBlock() function must return
EFI_INVALID_PARAMETER without modifying the contents of the firmware volume.
@param [in] This Pointer to EFI_SMM_FW_BLOCK_SERVICE_PROTOCOL instance.
@param [in] LbaWriteAddress Start address to be erased.
@param [in, out] NumBytes IN: The requested erase size.
OUT: The data size by bytes has been erased.
@retval EFI_SUCCESS Erase data successful.
@retval EFI_INVALID_PARAMETER Input function parameters are invalid.
@retval EFI_UNSUPPORTED The flash device is not supported
@retval EFI_DEVICE_ERROR Erase data failed caused by device error.
**/
EFI_STATUS
EFIAPI
FlashFdEraseBlocks (
IN EFI_SMM_FW_BLOCK_SERVICE_PROTOCOL *This,
IN UINTN WriteAddress,
IN UINTN *NumBytes
)
{
return FlashErase (WriteAddress, *NumBytes);
}
/**
The GetFlashTable() function get flash region table from platform.
if the descriptor is valid, the FlashTable will be filled.
if the descriptor is invalid,the FlashTable will be filled RegionTypeEos(0xff) directly.
@param [in] This Pointer to EFI_SMM_FW_BLOCK_SERVICE_PROTOCOL instance.
@param [in, out] FlashTable IN: Input buffer which want to save flash table.
OUT: Buffer to save flash table.
@retval EFI_SUCCESS Get flash table successful.
@retval EFI_UNSUPPORTED Flash device doesn't support this feature.
**/
EFI_STATUS
EFIAPI
FlashFdGetFlashTable (
IN EFI_SMM_FW_BLOCK_SERVICE_PROTOCOL *This,
IN OUT UINT8 *FlashTable
)
{
return GetPlatformFlashTable (FlashTable);
}
/**
Get Platform SPI Flash Number from SPI descriptor
@param [in] This Pointer to EFI_SMM_FW_BLOCK_SERVICE_PROTOCOL instance.
@param [out] FlashNumber Number of SPI flash devices returned.
@retval EFI_SUCCESS Successfully returns.
@retval EFI_UNSUPPORTED Platform is not using SPI flash rom or SPI is not in descriptor mode.
**/
EFI_STATUS
EFIAPI
FlashFdGetSpiFlashNumber (
IN EFI_SMM_FW_BLOCK_SERVICE_PROTOCOL *This,
OUT UINT8 *FlashNumber
)
{
return GetPlatformSpiFlashNumber (FlashNumber);
}
/**
Convert address for SPI descriptor mode
@param [in] This Pointer to EFI_SMM_FW_BLOCK_SERVICE_PROTOCOL instance.
@param[in] MemAddress BIOS memory mapped address.
@param[out] SpiAddress Flash ROM start address + BIOS address in flash ROM.
@retval EFI_SUCCESS Successfully returns.
@retval EFI_UNSUPPORT Platform is not using SPI ROM.
The SPI flash is not in Descriptor mode.
The input address does not belong to BIOS memory mapped region.
**/
EFI_STATUS
EFIAPI
FlashFdConvertToSpiAddress (
IN EFI_SMM_FW_BLOCK_SERVICE_PROTOCOL *This,
IN UINTN MemAddress,
OUT UINTN *SpiAddress
)
{
return ConvertToSpiAddress (MemAddress, SpiAddress);
}
/**
Initialize the communicate buffer using DataSize and Function.
The communicate size is: SMM_FWB_COMMUNICATE_ACCESS_FVB_SIZE.
@param[in] Function The function number to initialize the communicate header.
@param[out] DataPtr Points to the data in the communicate buffer.
@retval EFI_SUCCESS Find the specified variable.
@retval EFI_INVALID_PARAMETER The data size is too big.
**/
EFI_STATUS
InitCommunicateBuffer (
IN UINTN Function,
OUT VOID **DataPtr OPTIONAL
)
{
EFI_SMM_COMMUNICATE_HEADER *SmmCommunicateHeader;
SMM_FWB_COMMUNICATE_HEADER *SmmFwbFunctionHeader;
SmmCommunicateHeader = (EFI_SMM_COMMUNICATE_HEADER *) mFwbBuffer;
CopyGuid (&SmmCommunicateHeader->HeaderGuid, &gEfiSmmFwBlockServiceProtocolGuid);
SmmCommunicateHeader->MessageLength = SMM_FWB_COMMUNICATE_ACCESS_FVB_SIZE + BLOCK_SIZE - SMM_COMMUNICATE_HEADER_SIZE;
SmmFwbFunctionHeader = (SMM_FWB_COMMUNICATE_HEADER *) SmmCommunicateHeader->Data;
SmmFwbFunctionHeader->Function = Function;
if (DataPtr != NULL) {
*DataPtr = SmmFwbFunctionHeader->Data;
}
return EFI_SUCCESS;
}
/**
Send the data in communicate buffer to SMM.
@retval EFI_SUCCESS Success is returned from the functin in SMM.
@retval Others Failure is returned from the function in SMM.
**/
EFI_STATUS
SendCommunicateBuffer (
VOID
)
{
EFI_STATUS Status;
UINTN CommSize;
EFI_SMM_COMMUNICATE_HEADER *SmmCommunicateHeader;
SMM_FWB_COMMUNICATE_HEADER *SmmFwbFunctionHeader;
CommSize = SMM_FWB_COMMUNICATE_ACCESS_FVB_SIZE + BLOCK_SIZE;
Status = mSmmCommunication->Communicate (mSmmCommunication, mFwbBuffer, &CommSize);
ASSERT_EFI_ERROR (Status);
SmmCommunicateHeader = (EFI_SMM_COMMUNICATE_HEADER *) mFwbBuffer;
SmmFwbFunctionHeader = (SMM_FWB_COMMUNICATE_HEADER *) SmmCommunicateHeader->Data;
return SmmFwbFunctionHeader->ReturnStatus;
}
/**
Detect target flash device and copy whole flash device to output buffer.
This function always returns EFI_UNSUPPORTED.
@param[in] This Pointer to EFI_SMM_FW_BLOCK_SERVICE_PROTOCOL instance.
@param[out] SystemTable Buffer to saved target flash device information
@retval EFI_UNSUPPORTED Always return EFI_UNSUPPORTED.
**/
EFI_STATUS
EFIAPI
BsFlashFdDetectDevice (
IN EFI_SMM_FW_BLOCK_SERVICE_PROTOCOL *This,
OUT UINT8 *Buffer
)
{
return EFI_UNSUPPORTED;
}
/**
Reads data beginning at Lba:Offset from FV and places the data in Buffer.
The read terminates either when *NumBytes of data have been read, or when
a block boundary is reached. *NumBytes is updated to reflect the actual
number of bytes read.
@param [in] This Pointer to EFI_SMM_FW_BLOCK_SERVICE_PROTOCOL instance.
@param [in] WriteAddress Start LBA address which want to read.
@param [in] Offset Offset in the block at which to begin read
@param [in, out] NumBytes IN: The requested read size.
OUT: The data size by bytes has been read
@param [out] Buffer Data buffer in which to place data read.
@retval EFI_SUCCESS Read data successful.
@retval EFI_INVALID_PARAMETER Input function parameters are invalid.
@retval EFI_UNSUPPORTED The flash device is not supported
@retval EFI_DEVICE_ERROR Read data failed caused by device error.
**/
EFI_STATUS
EFIAPI
BsFlashFdRead (
IN EFI_SMM_FW_BLOCK_SERVICE_PROTOCOL *This,
IN UINTN WriteAddress,
IN UINTN Offset,
IN OUT UINTN *NumBytes,
OUT UINT8 *Buffer
)
{
SMM_FWB_COMMUNICATE_ACCESS_FVB *FwbAccessHeader;
UINTN ReadBytes;
EFI_STATUS Status;
InitCommunicateBuffer (SMM_FWB_FUNCTION_READ, (VOID **) &FwbAccessHeader);
if (FwbAccessHeader == NULL) {
return EFI_UNSUPPORTED;
}
for (ReadBytes = 0; ReadBytes + BLOCK_SIZE < *NumBytes; ReadBytes += BLOCK_SIZE) {
FwbAccessHeader->Address = WriteAddress + Offset + ReadBytes;
FwbAccessHeader->NumBytes = BLOCK_SIZE;
Status = SendCommunicateBuffer ();
if (EFI_ERROR (Status)) {
return Status;
}
CopyMem (Buffer + ReadBytes, FwbAccessHeader + 1, BLOCK_SIZE);
}
if (ReadBytes != *NumBytes) {
FwbAccessHeader->Address = WriteAddress + Offset + ReadBytes;
FwbAccessHeader->NumBytes = *NumBytes - ReadBytes;
Status = SendCommunicateBuffer ();
if (EFI_ERROR (Status)) {
return Status;
}
CopyMem (Buffer + ReadBytes, FwbAccessHeader + 1, *NumBytes - ReadBytes);
}
return EFI_SUCCESS;
}
/**
Writes data beginning at Lba:Offset from FV. The write terminates either
when *NumBytes of data have been written, or when a block boundary is
reached. *NumBytes is updated to reflect the actual number of bytes
written.
@param [in] This Pointer to EFI_SMM_FW_BLOCK_SERVICE_PROTOCOL instance.
@param [in] Offset Start address to be written.
@param [in, out] NumBytes IN: The requested write size.
OUT: The data size by bytes has been written.
@param [out] Buffer Data buffer want to write.
@retval EFI_SUCCESS Write data successful.
@retval EFI_INVALID_PARAMETER Input function parameters are invalid.
@retval EFI_UNSUPPORTED The flash device is not supported
@retval EFI_DEVICE_ERROR Write data failed caused by device error.
**/
EFI_STATUS
EFIAPI
BsFlashFdWrite (
IN EFI_SMM_FW_BLOCK_SERVICE_PROTOCOL *This,
IN UINTN WriteAddress,
IN OUT UINTN *NumBytes,
IN UINT8 *Buffer
)
{
SMM_FWB_COMMUNICATE_ACCESS_FVB *FwbAccessHeader;
UINTN WriteBytes;
EFI_STATUS Status;
InitCommunicateBuffer (SMM_FWB_FUNCTION_WRITE, (VOID **) &FwbAccessHeader);
if (FwbAccessHeader == NULL) {
return EFI_UNSUPPORTED;
}
for (WriteBytes = 0; WriteBytes + BLOCK_SIZE < *NumBytes; WriteBytes += BLOCK_SIZE) {
FwbAccessHeader->Address = WriteAddress + WriteBytes;
FwbAccessHeader->NumBytes = BLOCK_SIZE;
CopyMem (FwbAccessHeader + 1, Buffer + WriteBytes, BLOCK_SIZE);
Status = SendCommunicateBuffer ();
if (EFI_ERROR (Status)) {
return Status;
}
}
if (WriteBytes != *NumBytes) {
FwbAccessHeader->Address = WriteAddress + WriteBytes;
FwbAccessHeader->NumBytes = *NumBytes - WriteBytes;
CopyMem (FwbAccessHeader + 1, Buffer + WriteBytes, *NumBytes - WriteBytes);
Status = SendCommunicateBuffer ();
if (EFI_ERROR (Status)) {
return Status;
}
}
return EFI_SUCCESS;
}
/**
The EraseBlock() function erases one or more blocks as denoted by the
variable argument list. The entire parameter list of blocks must be verified
prior to erasing any blocks. If a block is requested that does not exist
within the associated firmware volume (it has a larger index than the last
block of the firmware volume), the EraseBlock() function must return
EFI_INVALID_PARAMETER without modifying the contents of the firmware volume.
@param [in] This Pointer to EFI_SMM_FW_BLOCK_SERVICE_PROTOCOL instance.
@param [in] LbaWriteAddress Start address to be erased.
@param [in, out] NumBytes IN: The requested erase size.
OUT: The data size by bytes has been erased.
@retval EFI_SUCCESS Erase data successful.
@retval EFI_INVALID_PARAMETER Input function parameters are invalid.
@retval EFI_UNSUPPORTED The flash device is not supported
@retval EFI_DEVICE_ERROR Erase data failed caused by device error.
**/
EFI_STATUS
EFIAPI
BsFlashFdEraseBlocks (
IN EFI_SMM_FW_BLOCK_SERVICE_PROTOCOL *This,
IN UINTN WriteAddress,
IN UINTN *NumBytes
)
{
SMM_FWB_COMMUNICATE_ACCESS_FVB *FwbAccessHeader;
InitCommunicateBuffer (SMM_FWB_FUNCTION_ERASE_BLOCKS, (VOID **) &FwbAccessHeader);
if (FwbAccessHeader == NULL) {
return EFI_UNSUPPORTED;
}
FwbAccessHeader->Address = WriteAddress;
FwbAccessHeader->NumBytes = *NumBytes;
return SendCommunicateBuffer ();
}
/**
The GetFlashTable() function get flash region table from platform.
if the descriptor is valid, the FlashTable will be filled.
if the descriptor is invalid,the FlashTable will be filled RegionTypeEos(0xff) directly.
This function always returns EFI_UNSUPPORTED.
@param [in] This Pointer to EFI_SMM_FW_BLOCK_SERVICE_PROTOCOL instance.
@param [in, out] FlashTable IN: Input buffer which want to save flash table.
OUT: Buffer to save flash table.
@retval EFI_UNSUPPORTED Always return EFI_UNSUPPORTED.
**/
EFI_STATUS
EFIAPI
BsFlashFdGetFlashTable (
IN EFI_SMM_FW_BLOCK_SERVICE_PROTOCOL *This,
IN OUT UINT8 *FlashTable
)
{
return EFI_UNSUPPORTED;
}
/**
Get Platform SPI Flash Number from SPI descriptor
This function always returns EFI_UNSUPPORTED.
@param [in] This Pointer to EFI_SMM_FW_BLOCK_SERVICE_PROTOCOL instance.
@param [out] FlashNumber Number of SPI flash devices returned.
@retval EFI_UNSUPPORT Always return EFI_UNSUPPORTED.
**/
EFI_STATUS
EFIAPI
BsFlashFdGetSpiFlashNumber (
IN EFI_SMM_FW_BLOCK_SERVICE_PROTOCOL *This,
OUT UINT8 *FlashNumber
)
{
return EFI_UNSUPPORTED;
}
/**
Convert address for SPI descriptor mode
This function always returns EFI_UNSUPPORTED.
@param [in] This Pointer to EFI_SMM_FW_BLOCK_SERVICE_PROTOCOL instance.
@param[in] MemAddress BIOS memory mapped address.
@param[out] SpiAddress Flash ROM start address + BIOS address in flash ROM.
@retval EFI_UNSUPPORT Always return EFI_UNSUPPORTED.
**/
EFI_STATUS
EFIAPI
BsFlashFdConvertToSpiAddress (
IN EFI_SMM_FW_BLOCK_SERVICE_PROTOCOL *This,
IN UINTN MemAddress,
OUT UINTN *SpiAddress
)
{
return EFI_UNSUPPORTED;
}