/**
  Read from working block to refresh the work space in memory.

  @param FtwDevice   Point to private data of FTW driver

  @retval  EFI_SUCCESS    The function completed successfully
  @retval  EFI_ABORTED    The function could not complete successfully.

**/
EFI_STATUS
WorkSpaceRefresh (
  IN EFI_FTW_DEVICE  *FtwDevice
  )
{
  EFI_STATUS                      Status;
  UINTN                           Length;
  UINTN                           RemainingSpaceSize;

  //
  // Initialize WorkSpace as FTW_ERASED_BYTE
  //
  SetMem (
    FtwDevice->FtwWorkSpace,
    FtwDevice->FtwWorkSpaceSize,
    FTW_ERASED_BYTE
    );

  //
  // Read from working block
  //
  Length = FtwDevice->FtwWorkSpaceSize;
  Status = FtwDevice->FtwFvBlock->Read (
                                    FtwDevice->FtwFvBlock,
                                    FtwDevice->FtwWorkSpaceLba,
                                    FtwDevice->FtwWorkSpaceBase,
                                    &Length,
                                    FtwDevice->FtwWorkSpace
                                    );
  if (EFI_ERROR (Status)) {
    return EFI_ABORTED;
  }
  //
  // Refresh the FtwLastWriteHeader
  //
  Status = FtwGetLastWriteHeader (
            FtwDevice->FtwWorkSpaceHeader,
            FtwDevice->FtwWorkSpaceSize,
            &FtwDevice->FtwLastWriteHeader
            );
  RemainingSpaceSize = FtwDevice->FtwWorkSpaceSize - ((UINTN) FtwDevice->FtwLastWriteHeader - (UINTN) FtwDevice->FtwWorkSpace);
  DEBUG ((EFI_D_INFO, "Ftw: Remaining work space size - %x\n", RemainingSpaceSize));
  //
  // If FtwGetLastWriteHeader() returns error, or the remaining space size is even not enough to contain
  // one EFI_FAULT_TOLERANT_WRITE_HEADER + one EFI_FAULT_TOLERANT_WRITE_RECORD(It will cause that the header
  // pointed by FtwDevice->FtwLastWriteHeader or record pointed by FtwDevice->FtwLastWriteRecord may contain invalid data),
  // it needs to reclaim work space.
  //
  if (EFI_ERROR (Status) || RemainingSpaceSize < sizeof (EFI_FAULT_TOLERANT_WRITE_HEADER) + sizeof (EFI_FAULT_TOLERANT_WRITE_RECORD)) {
    //
    // reclaim work space in working block.
    //
    Status = FtwReclaimWorkSpace (FtwDevice, TRUE);
    if (EFI_ERROR (Status)) {
      DEBUG ((EFI_D_ERROR, "Ftw: Reclaim workspace - %r\n", Status));
      return EFI_ABORTED;
    }
    //
    // Read from working block again
    //
    Length = FtwDevice->FtwWorkSpaceSize;
    Status = FtwDevice->FtwFvBlock->Read (
                                      FtwDevice->FtwFvBlock,
                                      FtwDevice->FtwWorkSpaceLba,
                                      FtwDevice->FtwWorkSpaceBase,
                                      &Length,
                                      FtwDevice->FtwWorkSpace
                                      );
    if (EFI_ERROR (Status)) {
      return EFI_ABORTED;
    }

    Status = FtwGetLastWriteHeader (
              FtwDevice->FtwWorkSpaceHeader,
              FtwDevice->FtwWorkSpaceSize,
              &FtwDevice->FtwLastWriteHeader
              );
    if (EFI_ERROR (Status)) {
      return EFI_ABORTED;
    }
  }
  //
  // Refresh the FtwLastWriteRecord
  //
  Status = FtwGetLastWriteRecord (
            FtwDevice->FtwLastWriteHeader,
            &FtwDevice->FtwLastWriteRecord
            );
  if (EFI_ERROR (Status)) {
    return EFI_ABORTED;
  }

  return EFI_SUCCESS;
}
Exemple #2
0
/**
  Allocates space for the protocol to maintain information about writes.
  Since writes must be completed in a fault tolerant manner and multiple
  updates will require more resources to be successful, this function
  enables the protocol to ensure that enough space exists to track
  information about the upcoming writes.

  All writes must be completed or aborted before another fault tolerant write can occur.

  @param This            The pointer to this protocol instance. 
  @param CallerId        The GUID identifying the write.
  @param PrivateDataSize The size of the caller's private data
                         that must be recorded for each write.
  @param NumberOfWrites  The number of fault tolerant block writes
                         that will need to occur.

  @return EFI_SUCCESS        The function completed successfully
  @retval EFI_ABORTED        The function could not complete successfully.
  @retval EFI_ACCESS_DENIED  All allocated writes have not been completed.

**/
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                           Length;
  UINTN                           Offset;
  EFI_FTW_DEVICE                  *FtwDevice;
  EFI_FAULT_TOLERANT_WRITE_HEADER *FtwHeader;

  FtwDevice = FTW_CONTEXT_FROM_THIS (This);

  Status    = WorkSpaceRefresh (FtwDevice);
  if (EFI_ERROR (Status)) {
    return EFI_ABORTED;
  }
  //
  // Check if there is enough space for the coming allocation
  //
  if (WRITE_TOTAL_SIZE (NumberOfWrites, PrivateDataSize) > FtwDevice->FtwWorkSpaceHeader->WriteQueueSize) {
    DEBUG ((EFI_D_ERROR, "Ftw: Allocate() request exceed Workspace, Caller: %g\n", CallerId));
    return EFI_BUFFER_TOO_SMALL;
  }
  //
  // Find the last write header and record.
  // If the FtwHeader is complete, skip the completed last write header/records
  //
  FtwHeader = FtwDevice->FtwLastWriteHeader;

  //
  // Previous write has not completed, access denied.
  //
  if ((FtwHeader->HeaderAllocated == FTW_VALID_STATE) || (FtwHeader->WritesAllocated == FTW_VALID_STATE)) {
    return EFI_ACCESS_DENIED;
  }
  //
  // If workspace is not enough, then reclaim workspace
  //
  Offset = (UINT8 *) FtwHeader - (UINT8 *) FtwDevice->FtwWorkSpace;
  if (Offset + WRITE_TOTAL_SIZE (NumberOfWrites, PrivateDataSize) > FtwDevice->FtwWorkSpaceSize) {
    Status = FtwReclaimWorkSpace (FtwDevice, TRUE);
    if (EFI_ERROR (Status)) {
      return EFI_ABORTED;
    }

    FtwHeader = FtwDevice->FtwLastWriteHeader;
  }
  //
  // Prepare FTW write header,
  // overwrite the buffer and write to workspace.
  //
  FtwHeader->WritesAllocated  = FTW_INVALID_STATE;
  FtwHeader->Complete         = FTW_INVALID_STATE;
  CopyMem (&FtwHeader->CallerId, CallerId, sizeof (EFI_GUID));
  FtwHeader->NumberOfWrites   = NumberOfWrites;
  FtwHeader->PrivateDataSize  = PrivateDataSize;
  FtwHeader->HeaderAllocated  = FTW_VALID_STATE;

  Length                      = sizeof (EFI_FAULT_TOLERANT_WRITE_HEADER);
  Status = FtwDevice->FtwFvBlock->Write (
                                    FtwDevice->FtwFvBlock,
                                    FtwDevice->FtwWorkSpaceLba,
                                    FtwDevice->FtwWorkSpaceBase + Offset,
                                    &Length,
                                    (UINT8 *) FtwHeader
                                    );
  if (EFI_ERROR (Status)) {
    return EFI_ABORTED;
  }
  //
  // Update Header->WriteAllocated as VALID
  //
  Status = FtwUpdateFvState (
            FtwDevice->FtwFvBlock,
            FtwDevice->FtwWorkSpaceLba,
            FtwDevice->FtwWorkSpaceBase + Offset,
            WRITES_ALLOCATED
            );
  if (EFI_ERROR (Status)) {
    return EFI_ABORTED;
  }

  DEBUG (
    (EFI_D_ERROR,
    "Ftw: Allocate() success, Caller:%g, # %d\n",
    CallerId,
    NumberOfWrites)
    );

  return EFI_SUCCESS;
}
Exemple #3
0
EFI_STATUS
WorkSpaceRefresh (
  IN EFI_FTW_LITE_DEVICE  *FtwLiteDevice
  )
/*++

Routine Description:
    Read from working block to refresh the work space in memory.

Arguments:
    FtwLiteDevice     - Point to private data of FTW driver

Returns:
    EFI_SUCCESS   - The function completed successfully
    EFI_ABORTED   - The function could not complete successfully.

--*/
{
  EFI_STATUS          Status;
  UINTN               Length;
  UINTN               Offset;
  EFI_FTW_LITE_RECORD *Record;

  //
  // Initialize WorkSpace as FTW_ERASED_BYTE
  //
  EfiSetMem (
    FtwLiteDevice->FtwWorkSpace,
    FtwLiteDevice->FtwWorkSpaceSize,
    FTW_ERASED_BYTE
    );

  //
  // Read from working block
  //
  Length = FtwLiteDevice->FtwWorkSpaceSize;
  Status = FtwLiteDevice->FtwFvBlock->Read (
                                        FtwLiteDevice->FtwFvBlock,
                                        FtwLiteDevice->FtwWorkSpaceLba,
                                        FtwLiteDevice->FtwWorkSpaceBase,
                                        &Length,
                                        FtwLiteDevice->FtwWorkSpace
                                        );
  if (EFI_ERROR (Status)) {
    return EFI_ABORTED;
  }
  //
  // Refresh the FtwLastRecord
  //
  Status  = FtwGetLastRecord (FtwLiteDevice, &FtwLiteDevice->FtwLastRecord);

  Record  = FtwLiteDevice->FtwLastRecord;
  Offset  = (UINTN) (UINT8 *) Record - (UINTN) FtwLiteDevice->FtwWorkSpace;

  //
  // IF work space has error or Record is out of the workspace limit, THEN
  //   call reclaim.
  //
  if (EFI_ERROR (Status) || (Offset + WRITE_TOTAL_SIZE >= FtwLiteDevice->FtwWorkSpaceSize)) {
    //
    // reclaim work space in working block.
    //
    Status = FtwReclaimWorkSpace (FtwLiteDevice, TRUE);
    if (EFI_ERROR (Status)) {
      DEBUG ((EFI_D_FTW_LITE, "FtwLite: Reclaim workspace - %r\n", Status));
      return EFI_ABORTED;
    }
  }

  return EFI_SUCCESS;
}