mirror of
				https://git.proxmox.com/git/mirror_edk2
				synced 2025-11-04 11:29:11 +00:00 
			
		
		
		
	1. Do not use tab characters 2. No trailing white space in one line 3. All files must end with CRLF Contributed-under: TianoCore Contribution Agreement 1.1 Signed-off-by: Liming Gao <liming.gao@intel.com> Reviewed-by: Star Zeng <star.zeng@intel.com>
		
			
				
	
	
		
			563 lines
		
	
	
		
			20 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			563 lines
		
	
	
		
			20 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/** @file
 | 
						|
 | 
						|
  Implement the Fault Tolerant Write (FTW) protocol based on SMM FTW
 | 
						|
  module.
 | 
						|
 | 
						|
Copyright (c) 2011 - 2018, Intel Corporation. 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 "FaultTolerantWriteSmmDxe.h"
 | 
						|
 | 
						|
EFI_HANDLE                         mHandle                   = NULL;
 | 
						|
EFI_SMM_COMMUNICATION_PROTOCOL     *mSmmCommunication        = NULL;
 | 
						|
UINTN                              mPrivateDataSize          = 0;
 | 
						|
 | 
						|
EFI_FAULT_TOLERANT_WRITE_PROTOCOL  mFaultTolerantWriteDriver = {
 | 
						|
  FtwGetMaxBlockSize,
 | 
						|
  FtwAllocate,
 | 
						|
  FtwWrite,
 | 
						|
  FtwRestart,
 | 
						|
  FtwAbort,
 | 
						|
  FtwGetLastWrite
 | 
						|
};
 | 
						|
 | 
						|
/**
 | 
						|
  Initialize the communicate buffer using DataSize and Function number.
 | 
						|
 | 
						|
  @param[out]      CommunicateBuffer The communicate buffer. Caller should free it after use.
 | 
						|
  @param[out]      DataPtr           Points to the data in the communicate buffer. Caller should not free it.
 | 
						|
  @param[in]       DataSize          The payload size.
 | 
						|
  @param[in]       Function          The function number used to initialize the communicate header.
 | 
						|
 | 
						|
**/
 | 
						|
VOID
 | 
						|
InitCommunicateBuffer (
 | 
						|
  OUT     VOID                              **CommunicateBuffer,
 | 
						|
  OUT     VOID                              **DataPtr,
 | 
						|
  IN      UINTN                             DataSize,
 | 
						|
  IN      UINTN                             Function
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_SMM_COMMUNICATE_HEADER                *SmmCommunicateHeader;
 | 
						|
  SMM_FTW_COMMUNICATE_FUNCTION_HEADER       *SmmFtwFunctionHeader;
 | 
						|
 | 
						|
  //
 | 
						|
  // The whole buffer size: SMM_COMMUNICATE_HEADER_SIZE + SMM_FTW_COMMUNICATE_HEADER_SIZE + DataSize.
 | 
						|
  //
 | 
						|
  SmmCommunicateHeader = AllocateZeroPool (DataSize + SMM_COMMUNICATE_HEADER_SIZE + SMM_FTW_COMMUNICATE_HEADER_SIZE);
 | 
						|
  ASSERT (SmmCommunicateHeader != NULL);
 | 
						|
 | 
						|
  //
 | 
						|
  // Prepare data buffer.
 | 
						|
  //
 | 
						|
  CopyGuid (&SmmCommunicateHeader->HeaderGuid, &gEfiSmmFaultTolerantWriteProtocolGuid);
 | 
						|
  SmmCommunicateHeader->MessageLength = DataSize + SMM_FTW_COMMUNICATE_HEADER_SIZE;
 | 
						|
 | 
						|
  SmmFtwFunctionHeader = (SMM_FTW_COMMUNICATE_FUNCTION_HEADER *) SmmCommunicateHeader->Data;
 | 
						|
  SmmFtwFunctionHeader->Function = Function;
 | 
						|
 | 
						|
  *CommunicateBuffer = SmmCommunicateHeader;
 | 
						|
  if (DataPtr != NULL) {
 | 
						|
    *DataPtr = SmmFtwFunctionHeader->Data;
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/**
 | 
						|
  Send the data in communicate buffer to SMI handler and get response.
 | 
						|
 | 
						|
  @param[in, out]  SmmCommunicateHeader    The communicate buffer.
 | 
						|
  @param[in]       DataSize                The payload size.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
SendCommunicateBuffer (
 | 
						|
  IN OUT  EFI_SMM_COMMUNICATE_HEADER        *SmmCommunicateHeader,
 | 
						|
  IN      UINTN                             DataSize
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_STATUS                                Status;
 | 
						|
  UINTN                                     CommSize;
 | 
						|
  SMM_FTW_COMMUNICATE_FUNCTION_HEADER       *SmmFtwFunctionHeader;
 | 
						|
 | 
						|
  CommSize = DataSize + SMM_COMMUNICATE_HEADER_SIZE + SMM_FTW_COMMUNICATE_HEADER_SIZE;
 | 
						|
  Status = mSmmCommunication->Communicate (mSmmCommunication, SmmCommunicateHeader, &CommSize);
 | 
						|
  ASSERT_EFI_ERROR (Status);
 | 
						|
 | 
						|
  SmmFtwFunctionHeader = (SMM_FTW_COMMUNICATE_FUNCTION_HEADER *) SmmCommunicateHeader->Data;
 | 
						|
  return  SmmFtwFunctionHeader->ReturnStatus;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/**
 | 
						|
  Get the FvbBaseAddress and FvbAttributes from the FVB handle FvbHandle.
 | 
						|
 | 
						|
  @param[in]   FvbHandle         The handle of FVB protocol that provides services.
 | 
						|
  @param[out]  FvbBaseAddress    The base address of the FVB attached with FvbHandle.
 | 
						|
  @param[out]  FvbAttributes     The attributes of the FVB attached with FvbHandle.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS            The function completed successfully.
 | 
						|
  @retval Others                 The function could not complete successfully.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
ConvertFvbHandle (
 | 
						|
  IN  EFI_HANDLE                            FvbHandle,
 | 
						|
  OUT EFI_PHYSICAL_ADDRESS                  *FvbBaseAddress,
 | 
						|
  OUT EFI_FVB_ATTRIBUTES_2                  *FvbAttributes
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_STATUS                                Status;
 | 
						|
  EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL        *Fvb;
 | 
						|
 | 
						|
  Status = gBS->HandleProtocol (FvbHandle, &gEfiFirmwareVolumeBlockProtocolGuid, (VOID **) &Fvb);
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    return Status;
 | 
						|
  }
 | 
						|
 | 
						|
  Status = Fvb->GetPhysicalAddress (Fvb, FvbBaseAddress);
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    return Status;
 | 
						|
  }
 | 
						|
 | 
						|
  Status = Fvb->GetAttributes (Fvb, FvbAttributes);
 | 
						|
  return Status;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/**
 | 
						|
  Get the size of the largest block that can be updated in a fault-tolerant manner.
 | 
						|
 | 
						|
  @param[in]  This             Indicates a pointer to the calling context.
 | 
						|
  @param[out] BlockSize        A pointer to a caller-allocated UINTN that is
 | 
						|
                               updated to indicate the size of the largest block
 | 
						|
                               that can be updated.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS          The function completed successfully.
 | 
						|
  @retval EFI_ABORTED          The function could not complete successfully.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
EFIAPI
 | 
						|
FtwGetMaxBlockSize (
 | 
						|
  IN EFI_FAULT_TOLERANT_WRITE_PROTOCOL      *This,
 | 
						|
  OUT UINTN                                 *BlockSize
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_STATUS                                Status;
 | 
						|
  UINTN                                     PayloadSize;
 | 
						|
  EFI_SMM_COMMUNICATE_HEADER                *SmmCommunicateHeader;
 | 
						|
  SMM_FTW_GET_MAX_BLOCK_SIZE_HEADER         *SmmFtwBlockSizeHeader;
 | 
						|
 | 
						|
  //
 | 
						|
  // Initialize the communicate buffer.
 | 
						|
  //
 | 
						|
  PayloadSize  = sizeof (SMM_FTW_GET_MAX_BLOCK_SIZE_HEADER);
 | 
						|
  InitCommunicateBuffer ((VOID **)&SmmCommunicateHeader, (VOID **)&SmmFtwBlockSizeHeader, PayloadSize, FTW_FUNCTION_GET_MAX_BLOCK_SIZE);
 | 
						|
 | 
						|
  //
 | 
						|
  // Send data to SMM.
 | 
						|
  //
 | 
						|
  Status = SendCommunicateBuffer (SmmCommunicateHeader, PayloadSize);
 | 
						|
 | 
						|
  //
 | 
						|
  // Get data from SMM
 | 
						|
  //
 | 
						|
  *BlockSize = SmmFtwBlockSizeHeader->BlockSize;
 | 
						|
  FreePool (SmmCommunicateHeader);
 | 
						|
 | 
						|
  return Status;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/**
 | 
						|
  Allocates space for the protocol to maintain information about writes.
 | 
						|
  Since writes must be completed in a fault-tolerant manner and multiple
 | 
						|
  writes require more resources to be successful, this function
 | 
						|
  enables the protocol to ensure that enough space exists to track
 | 
						|
  information about upcoming writes.
 | 
						|
 | 
						|
  @param[in]  This             A pointer to the calling context.
 | 
						|
  @param[in]  CallerId         The GUID identifying the write.
 | 
						|
  @param[in]  PrivateDataSize  The size of the caller's private data  that must be
 | 
						|
                               recorded for each write.
 | 
						|
  @param[in]  NumberOfWrites   The number of fault tolerant block writes that will
 | 
						|
                               need to occur.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS          The function completed successfully
 | 
						|
  @retval EFI_ABORTED          The function could not complete successfully.
 | 
						|
  @retval EFI_ACCESS_DENIED    Not all allocated writes have been completed.  All
 | 
						|
                               writes must be completed or aborted before another
 | 
						|
                               fault tolerant write can occur.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
EFIAPI
 | 
						|
FtwAllocate (
 | 
						|
  IN EFI_FAULT_TOLERANT_WRITE_PROTOCOL      *This,
 | 
						|
  IN EFI_GUID                               *CallerId,
 | 
						|
  IN UINTN                                  PrivateDataSize,
 | 
						|
  IN UINTN                                  NumberOfWrites
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_STATUS                                Status;
 | 
						|
  UINTN                                     PayloadSize;
 | 
						|
  EFI_SMM_COMMUNICATE_HEADER                *SmmCommunicateHeader;
 | 
						|
  SMM_FTW_ALLOCATE_HEADER                   *SmmFtwAllocateHeader;
 | 
						|
 | 
						|
  //
 | 
						|
  // Initialize the communicate buffer.
 | 
						|
  //
 | 
						|
  PayloadSize  = sizeof (SMM_FTW_ALLOCATE_HEADER);
 | 
						|
  InitCommunicateBuffer ((VOID **)&SmmCommunicateHeader, (VOID **)&SmmFtwAllocateHeader, PayloadSize, FTW_FUNCTION_ALLOCATE);
 | 
						|
  CopyGuid (&SmmFtwAllocateHeader->CallerId, CallerId);
 | 
						|
  SmmFtwAllocateHeader->PrivateDataSize = PrivateDataSize;
 | 
						|
  SmmFtwAllocateHeader->NumberOfWrites  = NumberOfWrites;
 | 
						|
 | 
						|
  //
 | 
						|
  // Send data to SMM.
 | 
						|
  //
 | 
						|
  Status = SendCommunicateBuffer (SmmCommunicateHeader, PayloadSize);
 | 
						|
  if (!EFI_ERROR( Status)) {
 | 
						|
    mPrivateDataSize = PrivateDataSize;
 | 
						|
  }
 | 
						|
 | 
						|
  FreePool (SmmCommunicateHeader);
 | 
						|
  return Status;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/**
 | 
						|
  Starts a target block update. This records information about the write
 | 
						|
  in fault tolerant storage, and will complete the write in a recoverable
 | 
						|
  manner, ensuring at all times that either the original contents or
 | 
						|
  the modified contents are available.
 | 
						|
 | 
						|
  @param[in]  This             The calling context.
 | 
						|
  @param[in]  Lba              The logical block address of the target block.
 | 
						|
  @param[in]  Offset           The offset within the target block to place the
 | 
						|
                               data.
 | 
						|
  @param[in]  Length           The number of bytes to write to the target block.
 | 
						|
  @param[in]  PrivateData      A pointer to private data that the caller requires
 | 
						|
                               to complete any pending writes in the event of a
 | 
						|
                               fault.
 | 
						|
  @param[in]  FvBlockHandle    The handle of FVB protocol that provides services
 | 
						|
                               for reading, writing, and erasing the target block.
 | 
						|
  @param[in]  Buffer           The data to write.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS          The function completed successfully.
 | 
						|
  @retval EFI_ABORTED          The function could not complete successfully.
 | 
						|
  @retval EFI_BAD_BUFFER_SIZE  The write would span a block boundary, which is not
 | 
						|
                               a valid action.
 | 
						|
  @retval EFI_ACCESS_DENIED    No writes have been allocated.
 | 
						|
  @retval EFI_NOT_READY        The last write has not been completed. Restart()
 | 
						|
                               must be called to complete it.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
EFIAPI
 | 
						|
FtwWrite (
 | 
						|
  IN EFI_FAULT_TOLERANT_WRITE_PROTOCOL      *This,
 | 
						|
  IN EFI_LBA                                Lba,
 | 
						|
  IN UINTN                                  Offset,
 | 
						|
  IN UINTN                                  Length,
 | 
						|
  IN VOID                                   *PrivateData,
 | 
						|
  IN EFI_HANDLE                             FvBlockHandle,
 | 
						|
  IN VOID                                   *Buffer
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_STATUS                                Status;
 | 
						|
  UINTN                                     PayloadSize;
 | 
						|
  EFI_SMM_COMMUNICATE_HEADER                *SmmCommunicateHeader;
 | 
						|
  SMM_FTW_WRITE_HEADER                      *SmmFtwWriteHeader;
 | 
						|
 | 
						|
  //
 | 
						|
  // Initialize the communicate buffer.
 | 
						|
  //
 | 
						|
  PayloadSize  = OFFSET_OF (SMM_FTW_WRITE_HEADER, Data) + Length;
 | 
						|
  if (PrivateData != NULL) {
 | 
						|
    //
 | 
						|
    // The private data buffer size should be the same one in FtwAllocate API.
 | 
						|
    //
 | 
						|
    PayloadSize += mPrivateDataSize;
 | 
						|
  }
 | 
						|
  InitCommunicateBuffer ((VOID **)&SmmCommunicateHeader, (VOID **)&SmmFtwWriteHeader, PayloadSize, FTW_FUNCTION_WRITE);
 | 
						|
 | 
						|
  //
 | 
						|
  // FvBlockHandle can not be used in SMM environment. Here we get the FVB protocol first, then get FVB base address
 | 
						|
  // and its attribute. Send these information to SMM handler, the SMM handler will find the proper FVB to write data.
 | 
						|
  //
 | 
						|
  Status = ConvertFvbHandle (FvBlockHandle, &SmmFtwWriteHeader->FvbBaseAddress, &SmmFtwWriteHeader->FvbAttributes);
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    FreePool (SmmCommunicateHeader);
 | 
						|
    return EFI_ABORTED;
 | 
						|
  }
 | 
						|
 | 
						|
  SmmFtwWriteHeader->Lba    = Lba;
 | 
						|
  SmmFtwWriteHeader->Offset = Offset;
 | 
						|
  SmmFtwWriteHeader->Length = Length;
 | 
						|
  CopyMem (SmmFtwWriteHeader->Data, Buffer, Length);
 | 
						|
  if (PrivateData == NULL) {
 | 
						|
    SmmFtwWriteHeader->PrivateDataSize = 0;
 | 
						|
  } else {
 | 
						|
    SmmFtwWriteHeader->PrivateDataSize = mPrivateDataSize;
 | 
						|
    CopyMem (&SmmFtwWriteHeader->Data[Length], PrivateData, mPrivateDataSize);
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Send data to SMM.
 | 
						|
  //
 | 
						|
  Status = SendCommunicateBuffer (SmmCommunicateHeader, PayloadSize);
 | 
						|
  FreePool (SmmCommunicateHeader);
 | 
						|
  return Status;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/**
 | 
						|
  Restarts a previously interrupted write. The caller must provide the
 | 
						|
  block protocol needed to complete the interrupted write.
 | 
						|
 | 
						|
  @param[in]  This             The calling context.
 | 
						|
  @param[in]  FvBlockHandle    The handle of FVB protocol that provides services.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS          The function completed successfully.
 | 
						|
  @retval EFI_ABORTED          The function could not complete successfully.
 | 
						|
  @retval EFI_ACCESS_DENIED    No pending writes exist.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
EFIAPI
 | 
						|
FtwRestart (
 | 
						|
  IN EFI_FAULT_TOLERANT_WRITE_PROTOCOL      *This,
 | 
						|
  IN EFI_HANDLE                             FvBlockHandle
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_STATUS                                Status;
 | 
						|
  UINTN                                     PayloadSize;
 | 
						|
  EFI_SMM_COMMUNICATE_HEADER                *SmmCommunicateHeader;
 | 
						|
  SMM_FTW_RESTART_HEADER                    *SmmFtwRestartHeader;
 | 
						|
 | 
						|
  //
 | 
						|
  // Initialize the communicate buffer.
 | 
						|
  //
 | 
						|
  PayloadSize  = sizeof (SMM_FTW_RESTART_HEADER);
 | 
						|
  InitCommunicateBuffer ((VOID **)&SmmCommunicateHeader, (VOID **)&SmmFtwRestartHeader, PayloadSize, FTW_FUNCTION_RESTART);
 | 
						|
 | 
						|
  //
 | 
						|
  // FvBlockHandle can not be used in SMM environment. Here we get the FVB protocol first, then get FVB base address
 | 
						|
  // and its attribute. Send these information to SMM handler, the SMM handler will find the proper FVB to write data.
 | 
						|
  //
 | 
						|
  Status = ConvertFvbHandle (FvBlockHandle, &SmmFtwRestartHeader->FvbBaseAddress, &SmmFtwRestartHeader->FvbAttributes);
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    FreePool (SmmCommunicateHeader);
 | 
						|
    return EFI_ABORTED;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Send data to SMM.
 | 
						|
  //
 | 
						|
  Status = SendCommunicateBuffer (SmmCommunicateHeader, PayloadSize);
 | 
						|
  FreePool (SmmCommunicateHeader);
 | 
						|
  return Status;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/**
 | 
						|
  Aborts all previously allocated writes.
 | 
						|
 | 
						|
  @param[in]  This             The calling context.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS          The function completed successfully.
 | 
						|
  @retval EFI_ABORTED          The function could not complete successfully.
 | 
						|
  @retval EFI_NOT_FOUND        No allocated writes exist.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
EFIAPI
 | 
						|
FtwAbort (
 | 
						|
  IN EFI_FAULT_TOLERANT_WRITE_PROTOCOL      *This
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_STATUS                                Status;
 | 
						|
  EFI_SMM_COMMUNICATE_HEADER                *SmmCommunicateHeader;
 | 
						|
 | 
						|
  //
 | 
						|
  // Initialize the communicate buffer.
 | 
						|
  //
 | 
						|
  InitCommunicateBuffer ((VOID **)&SmmCommunicateHeader, NULL, 0, FTW_FUNCTION_ABORT);
 | 
						|
 | 
						|
  //
 | 
						|
  // Send data to SMM.
 | 
						|
  //
 | 
						|
  Status = SendCommunicateBuffer (SmmCommunicateHeader, 0);
 | 
						|
 | 
						|
  FreePool (SmmCommunicateHeader);
 | 
						|
  return Status;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/**
 | 
						|
  Starts a target block update. This function records information about the write
 | 
						|
  in fault-tolerant storage and completes the write in a recoverable
 | 
						|
  manner, ensuring at all times that either the original contents or
 | 
						|
  the modified contents are available.
 | 
						|
 | 
						|
  @param[in]      This            Indicates a pointer to the calling context.
 | 
						|
  @param[out]     CallerId        The GUID identifying the last write.
 | 
						|
  @param[out]     Lba             The logical block address of the last write.
 | 
						|
  @param[out]     Offset          The offset within the block of the last write.
 | 
						|
  @param[out]     Length          The length of the last write.
 | 
						|
  @param[in, out] PrivateDataSize On input, the size of the PrivateData buffer. On
 | 
						|
                                  output, the size of the private data stored for
 | 
						|
                                  this write.
 | 
						|
  @param[out]     PrivateData     A pointer to a buffer. The function will copy
 | 
						|
                                  PrivateDataSize bytes from the private data stored
 | 
						|
                                  for this write.
 | 
						|
  @param[out]     Complete        A Boolean value with TRUE indicating that the write
 | 
						|
                                  was completed.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS             The function completed successfully.
 | 
						|
  @retval EFI_ABORTED             The function could not complete successfully.
 | 
						|
  @retval EFI_NOT_FOUND           No allocated writes exist.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
EFIAPI
 | 
						|
FtwGetLastWrite (
 | 
						|
  IN EFI_FAULT_TOLERANT_WRITE_PROTOCOL      *This,
 | 
						|
  OUT EFI_GUID                              *CallerId,
 | 
						|
  OUT EFI_LBA                               *Lba,
 | 
						|
  OUT UINTN                                 *Offset,
 | 
						|
  OUT UINTN                                 *Length,
 | 
						|
  IN OUT UINTN                              *PrivateDataSize,
 | 
						|
  OUT VOID                                  *PrivateData,
 | 
						|
  OUT BOOLEAN                               *Complete
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_STATUS                                Status;
 | 
						|
  UINTN                                     PayloadSize;
 | 
						|
  EFI_SMM_COMMUNICATE_HEADER                *SmmCommunicateHeader;
 | 
						|
  SMM_FTW_GET_LAST_WRITE_HEADER             *SmmFtwGetLastWriteHeader;
 | 
						|
 | 
						|
  //
 | 
						|
  // Initialize the communicate buffer.
 | 
						|
  //
 | 
						|
  PayloadSize  = OFFSET_OF (SMM_FTW_GET_LAST_WRITE_HEADER, Data) + *PrivateDataSize;
 | 
						|
  InitCommunicateBuffer ((VOID **)&SmmCommunicateHeader, (VOID **)&SmmFtwGetLastWriteHeader, PayloadSize, FTW_FUNCTION_GET_LAST_WRITE);
 | 
						|
  SmmFtwGetLastWriteHeader->PrivateDataSize = *PrivateDataSize;
 | 
						|
 | 
						|
  //
 | 
						|
  // Send data to SMM.
 | 
						|
  //
 | 
						|
  Status = SendCommunicateBuffer (SmmCommunicateHeader, PayloadSize);
 | 
						|
 | 
						|
  //
 | 
						|
  // Get data from SMM
 | 
						|
  //
 | 
						|
  *PrivateDataSize = SmmFtwGetLastWriteHeader->PrivateDataSize;
 | 
						|
  if (Status == EFI_SUCCESS || Status == EFI_BUFFER_TOO_SMALL) {
 | 
						|
    *Lba      = SmmFtwGetLastWriteHeader->Lba;
 | 
						|
    *Offset   = SmmFtwGetLastWriteHeader->Offset;
 | 
						|
    *Length   = SmmFtwGetLastWriteHeader->Length;
 | 
						|
    *Complete = SmmFtwGetLastWriteHeader->Complete;
 | 
						|
    CopyGuid (CallerId, &SmmFtwGetLastWriteHeader->CallerId);
 | 
						|
    if (Status == EFI_SUCCESS) {
 | 
						|
      CopyMem (PrivateData, SmmFtwGetLastWriteHeader->Data, *PrivateDataSize);
 | 
						|
    }
 | 
						|
  } else if (Status == EFI_NOT_FOUND) {
 | 
						|
    *Complete = SmmFtwGetLastWriteHeader->Complete;
 | 
						|
  }
 | 
						|
 | 
						|
  FreePool (SmmCommunicateHeader);
 | 
						|
  return Status;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  SMM Fault Tolerant Write Protocol notification event handler.
 | 
						|
 | 
						|
  Install Fault Tolerant Write Protocol.
 | 
						|
 | 
						|
  @param[in] Event    Event whose notification function is being invoked.
 | 
						|
  @param[in] Context  Pointer to the notification function's context.
 | 
						|
**/
 | 
						|
VOID
 | 
						|
EFIAPI
 | 
						|
SmmFtwReady (
 | 
						|
  IN  EFI_EVENT                             Event,
 | 
						|
  IN  VOID                                  *Context
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_STATUS                                Status;
 | 
						|
  EFI_FAULT_TOLERANT_WRITE_PROTOCOL         *FtwProtocol;
 | 
						|
 | 
						|
  //
 | 
						|
  // Just return to avoid install SMM FaultTolerantWriteProtocol again
 | 
						|
  // if Fault Tolerant Write protocol had been installed.
 | 
						|
  //
 | 
						|
  Status = gBS->LocateProtocol (&gEfiFaultTolerantWriteProtocolGuid, NULL, (VOID **)&FtwProtocol);
 | 
						|
  if (!EFI_ERROR (Status)) {
 | 
						|
    return;
 | 
						|
  }
 | 
						|
 | 
						|
  Status = gBS->LocateProtocol (&gEfiSmmCommunicationProtocolGuid, NULL, (VOID **) &mSmmCommunication);
 | 
						|
  ASSERT_EFI_ERROR (Status);
 | 
						|
 | 
						|
  //
 | 
						|
  // Install protocol interface
 | 
						|
  //
 | 
						|
  Status = gBS->InstallProtocolInterface (
 | 
						|
                  &mHandle,
 | 
						|
                  &gEfiFaultTolerantWriteProtocolGuid,
 | 
						|
                  EFI_NATIVE_INTERFACE,
 | 
						|
                  &mFaultTolerantWriteDriver
 | 
						|
                  );
 | 
						|
  ASSERT_EFI_ERROR (Status);
 | 
						|
 | 
						|
  Status = gBS->CloseEvent (Event);
 | 
						|
  ASSERT_EFI_ERROR (Status);
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/**
 | 
						|
  The driver entry point for Fault Tolerant Write driver.
 | 
						|
 | 
						|
  The function does the necessary initialization work.
 | 
						|
 | 
						|
  @param[in]  ImageHandle       The firmware allocated handle for the UEFI image.
 | 
						|
  @param[in]  SystemTable       A pointer to the EFI system table.
 | 
						|
 | 
						|
  @retval     EFI_SUCCESS       This funtion always return EFI_SUCCESS.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
EFIAPI
 | 
						|
FaultTolerantWriteSmmInitialize (
 | 
						|
  IN EFI_HANDLE                             ImageHandle,
 | 
						|
  IN EFI_SYSTEM_TABLE                       *SystemTable
 | 
						|
  )
 | 
						|
{
 | 
						|
  VOID                                      *SmmFtwRegistration;
 | 
						|
 | 
						|
  //
 | 
						|
  // Smm FTW driver is ready
 | 
						|
  //
 | 
						|
  EfiCreateProtocolNotifyEvent (
 | 
						|
    &gEfiSmmFaultTolerantWriteProtocolGuid,
 | 
						|
    TPL_CALLBACK,
 | 
						|
    SmmFtwReady,
 | 
						|
    NULL,
 | 
						|
    &SmmFtwRegistration
 | 
						|
    );
 | 
						|
 | 
						|
  return EFI_SUCCESS;
 | 
						|
}
 | 
						|
 |