Example #1
0
/**
  Communication service SMI Handler entry.

  This SMI handler provides services for the fault tolerant write wrapper driver.

  Caution: This function requires additional review when modified.
  This driver need to make sure the CommBuffer is not in the SMRAM range. 
  Also in FTW_FUNCTION_GET_LAST_WRITE case, check SmmFtwGetLastWriteHeader->Data + 
  SmmFtwGetLastWriteHeader->PrivateDataSize within communication buffer.

  @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
SmmFaultTolerantWriteHandler (
  IN     EFI_HANDLE                                DispatchHandle,
  IN     CONST VOID                                *RegisterContext,
  IN OUT VOID                                      *CommBuffer,
  IN OUT UINTN                                     *CommBufferSize
  )
{
  EFI_STATUS                                       Status;
  SMM_FTW_COMMUNICATE_FUNCTION_HEADER              *SmmFtwFunctionHeader;
  SMM_FTW_GET_MAX_BLOCK_SIZE_HEADER                *SmmGetMaxBlockSizeHeader;
  SMM_FTW_ALLOCATE_HEADER                          *SmmFtwAllocateHeader;
  SMM_FTW_WRITE_HEADER                             *SmmFtwWriteHeader;
  SMM_FTW_RESTART_HEADER                           *SmmFtwRestartHeader;
  SMM_FTW_GET_LAST_WRITE_HEADER                    *SmmFtwGetLastWriteHeader;
  VOID                                             *PrivateData;
  EFI_HANDLE                                       SmmFvbHandle;
  UINTN                                            InfoSize;


  //
  // If input is invalid, stop processing this SMI
  //
  if (CommBuffer == NULL || CommBufferSize == NULL) {
    return EFI_SUCCESS;
  }

  if (*CommBufferSize < SMM_FTW_COMMUNICATE_HEADER_SIZE) {
    return EFI_SUCCESS;
  }

  if (InternalIsAddressInSmram ((EFI_PHYSICAL_ADDRESS)(UINTN)CommBuffer, *CommBufferSize)) {
    DEBUG ((EFI_D_ERROR, "SMM communication buffer size is in SMRAM!\n"));
    return EFI_SUCCESS;
  }

  SmmFtwFunctionHeader = (SMM_FTW_COMMUNICATE_FUNCTION_HEADER *)CommBuffer;
  switch (SmmFtwFunctionHeader->Function) {
    case FTW_FUNCTION_GET_MAX_BLOCK_SIZE:
      SmmGetMaxBlockSizeHeader = (SMM_FTW_GET_MAX_BLOCK_SIZE_HEADER *) SmmFtwFunctionHeader->Data;
      InfoSize = sizeof (SMM_FTW_GET_MAX_BLOCK_SIZE_HEADER);

      //
      // SMRAM range check already covered before
      //
      if (InfoSize > *CommBufferSize - SMM_FTW_COMMUNICATE_HEADER_SIZE) {
        DEBUG ((EFI_D_ERROR, "Data size exceed communication buffer size limit!\n"));
        Status = EFI_ACCESS_DENIED;
        break;
      }

      Status = FtwGetMaxBlockSize (
                 &mFtwDevice->FtwInstance,
                 &SmmGetMaxBlockSizeHeader->BlockSize
                 );
      break;
      
    case FTW_FUNCTION_ALLOCATE:
      SmmFtwAllocateHeader = (SMM_FTW_ALLOCATE_HEADER *) SmmFtwFunctionHeader->Data;
      Status = FtwAllocate (
                 &mFtwDevice->FtwInstance,
                 &SmmFtwAllocateHeader->CallerId,
                 SmmFtwAllocateHeader->PrivateDataSize,
                 SmmFtwAllocateHeader->NumberOfWrites
                 );
      break;
      
    case FTW_FUNCTION_WRITE:
      SmmFtwWriteHeader = (SMM_FTW_WRITE_HEADER *) SmmFtwFunctionHeader->Data;
      if (SmmFtwWriteHeader->PrivateDataSize == 0) {
        PrivateData = NULL;
      } else {
        PrivateData = (VOID *)&SmmFtwWriteHeader->Data[SmmFtwWriteHeader->Length];
      }
      Status = GetFvbByAddressAndAttribute (
                 SmmFtwWriteHeader->FvbBaseAddress, 
                 SmmFtwWriteHeader->FvbAttributes,
                 &SmmFvbHandle
                 );
      if (!EFI_ERROR (Status)) {
        Status = FtwWrite(
                   &mFtwDevice->FtwInstance,
                   SmmFtwWriteHeader->Lba,
                   SmmFtwWriteHeader->Offset,
                   SmmFtwWriteHeader->Length,
                   PrivateData,
                   SmmFvbHandle,
                   SmmFtwWriteHeader->Data
                   );
      }
      break;
      
    case FTW_FUNCTION_RESTART:
      SmmFtwRestartHeader = (SMM_FTW_RESTART_HEADER *) SmmFtwFunctionHeader->Data;
      Status = GetFvbByAddressAndAttribute (
                 SmmFtwRestartHeader->FvbBaseAddress, 
                 SmmFtwRestartHeader->FvbAttributes,
                 &SmmFvbHandle
                 );      
      if (!EFI_ERROR (Status)) {
        Status = FtwRestart (&mFtwDevice->FtwInstance, SmmFvbHandle);
      }
      break;

    case FTW_FUNCTION_ABORT:
      Status = FtwAbort (&mFtwDevice->FtwInstance);
      break;
      
    case FTW_FUNCTION_GET_LAST_WRITE:
      SmmFtwGetLastWriteHeader = (SMM_FTW_GET_LAST_WRITE_HEADER *) SmmFtwFunctionHeader->Data;
      InfoSize = OFFSET_OF (SMM_FTW_GET_LAST_WRITE_HEADER, Data) + SmmFtwGetLastWriteHeader->PrivateDataSize;

      //
      // SMRAM range check already covered before
      //
      if (InfoSize > *CommBufferSize - SMM_FTW_COMMUNICATE_HEADER_SIZE) {
        DEBUG ((EFI_D_ERROR, "Data size exceed communication buffer size limit!\n"));
        Status = EFI_ACCESS_DENIED;
        break;
      }

      Status = FtwGetLastWrite (
                 &mFtwDevice->FtwInstance,
                 &SmmFtwGetLastWriteHeader->CallerId,
                 &SmmFtwGetLastWriteHeader->Lba,
                 &SmmFtwGetLastWriteHeader->Offset,
                 &SmmFtwGetLastWriteHeader->Length,
                 &SmmFtwGetLastWriteHeader->PrivateDataSize,
                 (VOID *)SmmFtwGetLastWriteHeader->Data,
                 &SmmFtwGetLastWriteHeader->Complete
                 );
      break;

    default:
      Status = EFI_UNSUPPORTED;
  }

  SmmFtwFunctionHeader->ReturnStatus = Status;

  return EFI_SUCCESS;
}
Example #2
0
/**
  Communication service SMI Handler entry.

  This SMI handler provides services for the fault tolerant write wrapper driver.

  Caution: This function requires additional review when modified.
  This driver need to make sure the CommBuffer is not in the SMRAM range. 
  Also in FTW_FUNCTION_GET_LAST_WRITE case, check SmmFtwGetLastWriteHeader->Data + 
  SmmFtwGetLastWriteHeader->PrivateDataSize within communication buffer.

  @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
SmmFaultTolerantWriteHandler (
  IN     EFI_HANDLE                                DispatchHandle,
  IN     CONST VOID                                *RegisterContext,
  IN OUT VOID                                      *CommBuffer,
  IN OUT UINTN                                     *CommBufferSize
  )
{
  EFI_STATUS                                       Status;
  SMM_FTW_COMMUNICATE_FUNCTION_HEADER              *SmmFtwFunctionHeader;
  SMM_FTW_GET_MAX_BLOCK_SIZE_HEADER                *SmmGetMaxBlockSizeHeader;
  SMM_FTW_ALLOCATE_HEADER                          *SmmFtwAllocateHeader;
  SMM_FTW_WRITE_HEADER                             *SmmFtwWriteHeader;
  SMM_FTW_RESTART_HEADER                           *SmmFtwRestartHeader;
  SMM_FTW_GET_LAST_WRITE_HEADER                    *SmmFtwGetLastWriteHeader;
  VOID                                             *PrivateData;
  EFI_HANDLE                                       SmmFvbHandle;
  UINTN                                            InfoSize;
  UINTN                                            CommBufferPayloadSize;
  UINTN                                            PrivateDataSize;
  UINTN                                            Length;
  UINTN                                            TempCommBufferSize;

  //
  // If input is invalid, stop processing this SMI
  //
  if (CommBuffer == NULL || CommBufferSize == NULL) {
    return EFI_SUCCESS;
  }

  TempCommBufferSize = *CommBufferSize;

  if (TempCommBufferSize < SMM_FTW_COMMUNICATE_HEADER_SIZE) {
    DEBUG ((EFI_D_ERROR, "SmmFtwHandler: SMM communication buffer size invalid!\n"));
    return EFI_SUCCESS;
  }
  CommBufferPayloadSize = TempCommBufferSize - SMM_FTW_COMMUNICATE_HEADER_SIZE;

  if (!SmmIsBufferOutsideSmmValid ((UINTN)CommBuffer, TempCommBufferSize)) {
    DEBUG ((EFI_D_ERROR, "SmmFtwHandler: SMM communication buffer in SMRAM or overflow!\n"));
    return EFI_SUCCESS;
  }

  SmmFtwFunctionHeader = (SMM_FTW_COMMUNICATE_FUNCTION_HEADER *)CommBuffer;

  if (mEndOfDxe) {
    //
    // It will be not safe to expose the operations after End Of Dxe.
    //
    DEBUG ((EFI_D_ERROR, "SmmFtwHandler: Not safe to do the operation: %x after End Of Dxe, so access denied!\n", SmmFtwFunctionHeader->Function));
    SmmFtwFunctionHeader->ReturnStatus = EFI_ACCESS_DENIED;
    return EFI_SUCCESS;
  }

  switch (SmmFtwFunctionHeader->Function) {
    case FTW_FUNCTION_GET_MAX_BLOCK_SIZE:
      if (CommBufferPayloadSize < sizeof (SMM_FTW_GET_MAX_BLOCK_SIZE_HEADER)) {
        DEBUG ((EFI_D_ERROR, "GetMaxBlockSize: SMM communication buffer size invalid!\n"));
        return EFI_SUCCESS;
      }
      SmmGetMaxBlockSizeHeader = (SMM_FTW_GET_MAX_BLOCK_SIZE_HEADER *) SmmFtwFunctionHeader->Data;

      Status = FtwGetMaxBlockSize (
                 &mFtwDevice->FtwInstance,
                 &SmmGetMaxBlockSizeHeader->BlockSize
                 );
      break;
      
    case FTW_FUNCTION_ALLOCATE:
      if (CommBufferPayloadSize < sizeof (SMM_FTW_ALLOCATE_HEADER)) {
        DEBUG ((EFI_D_ERROR, "Allocate: SMM communication buffer size invalid!\n"));
        return EFI_SUCCESS;
      }
      SmmFtwAllocateHeader = (SMM_FTW_ALLOCATE_HEADER *) SmmFtwFunctionHeader->Data;
      Status = FtwAllocate (
                 &mFtwDevice->FtwInstance,
                 &SmmFtwAllocateHeader->CallerId,
                 SmmFtwAllocateHeader->PrivateDataSize,
                 SmmFtwAllocateHeader->NumberOfWrites
                 );
      break;
      
    case FTW_FUNCTION_WRITE:
      if (CommBufferPayloadSize < OFFSET_OF (SMM_FTW_WRITE_HEADER, Data)) {
        DEBUG ((EFI_D_ERROR, "Write: SMM communication buffer size invalid!\n"));
        return EFI_SUCCESS;
      }
      SmmFtwWriteHeader = (SMM_FTW_WRITE_HEADER *) SmmFtwFunctionHeader->Data;
      Length = SmmFtwWriteHeader->Length;
      PrivateDataSize = SmmFtwWriteHeader->PrivateDataSize;
      if (((UINTN)(~0) - Length < OFFSET_OF (SMM_FTW_WRITE_HEADER, Data)) ||
        ((UINTN)(~0) - PrivateDataSize < OFFSET_OF (SMM_FTW_WRITE_HEADER, Data) + Length)) {
        //
        // Prevent InfoSize overflow
        //
        Status = EFI_ACCESS_DENIED;
        break;
      }
      InfoSize = OFFSET_OF (SMM_FTW_WRITE_HEADER, Data) + Length + PrivateDataSize;

      //
      // SMRAM range check already covered before
      //
      if (InfoSize > CommBufferPayloadSize) {
        DEBUG ((EFI_D_ERROR, "Write: Data size exceed communication buffer size limit!\n"));
        Status = EFI_ACCESS_DENIED;
        break;
      }

      if (PrivateDataSize == 0) {
        PrivateData = NULL;
      } else {
        PrivateData = (VOID *)&SmmFtwWriteHeader->Data[Length];
      }
      Status = GetFvbByAddressAndAttribute (
                 SmmFtwWriteHeader->FvbBaseAddress, 
                 SmmFtwWriteHeader->FvbAttributes,
                 &SmmFvbHandle
                 );
      if (!EFI_ERROR (Status)) {
        Status = FtwWrite(
                   &mFtwDevice->FtwInstance,
                   SmmFtwWriteHeader->Lba,
                   SmmFtwWriteHeader->Offset,
                   Length,
                   PrivateData,
                   SmmFvbHandle,
                   SmmFtwWriteHeader->Data
                   );
      }
      break;
      
    case FTW_FUNCTION_RESTART:
      if (CommBufferPayloadSize < sizeof (SMM_FTW_RESTART_HEADER)) {
        DEBUG ((EFI_D_ERROR, "Restart: SMM communication buffer size invalid!\n"));
        return EFI_SUCCESS;
      }
      SmmFtwRestartHeader = (SMM_FTW_RESTART_HEADER *) SmmFtwFunctionHeader->Data;
      Status = GetFvbByAddressAndAttribute (
                 SmmFtwRestartHeader->FvbBaseAddress, 
                 SmmFtwRestartHeader->FvbAttributes,
                 &SmmFvbHandle
                 );      
      if (!EFI_ERROR (Status)) {
        Status = FtwRestart (&mFtwDevice->FtwInstance, SmmFvbHandle);
      }
      break;

    case FTW_FUNCTION_ABORT:
      Status = FtwAbort (&mFtwDevice->FtwInstance);
      break;
      
    case FTW_FUNCTION_GET_LAST_WRITE:
      if (CommBufferPayloadSize < OFFSET_OF (SMM_FTW_GET_LAST_WRITE_HEADER, Data)) {
        DEBUG ((EFI_D_ERROR, "GetLastWrite: SMM communication buffer size invalid!\n"));
        return EFI_SUCCESS;
      }
      SmmFtwGetLastWriteHeader = (SMM_FTW_GET_LAST_WRITE_HEADER *) SmmFtwFunctionHeader->Data;
      PrivateDataSize = SmmFtwGetLastWriteHeader->PrivateDataSize;
      if ((UINTN)(~0) - PrivateDataSize < OFFSET_OF (SMM_FTW_GET_LAST_WRITE_HEADER, Data)){
        //
        // Prevent InfoSize overflow
        //
        Status = EFI_ACCESS_DENIED;
        break;
      }
      InfoSize = OFFSET_OF (SMM_FTW_GET_LAST_WRITE_HEADER, Data) + PrivateDataSize;

      //
      // SMRAM range check already covered before
      //
      if (InfoSize > CommBufferPayloadSize) {
        DEBUG ((EFI_D_ERROR, "Data size exceed communication buffer size limit!\n"));
        Status = EFI_ACCESS_DENIED;
        break;
      }

      Status = FtwGetLastWrite (
                 &mFtwDevice->FtwInstance,
                 &SmmFtwGetLastWriteHeader->CallerId,
                 &SmmFtwGetLastWriteHeader->Lba,
                 &SmmFtwGetLastWriteHeader->Offset,
                 &SmmFtwGetLastWriteHeader->Length,
                 &PrivateDataSize,
                 (VOID *)SmmFtwGetLastWriteHeader->Data,
                 &SmmFtwGetLastWriteHeader->Complete
                 );
      SmmFtwGetLastWriteHeader->PrivateDataSize = PrivateDataSize;
      break;

    default:
      Status = EFI_UNSUPPORTED;
  }

  SmmFtwFunctionHeader->ReturnStatus = Status;

  return EFI_SUCCESS;
}