예제 #1
0
/**
  Implements EFI_BLOCK_IO_PROTOCOL.ReadBlocks() function.

  @param  This                   The EFI_BLOCK_IO_PROTOCOL instance.
  @param  MediaId                The media id that the write request is for.
  @param  LBA                    The starting logical block address to read from on the device.
                                 The caller is responsible for writing to only legitimate locations.
  @param  BufferSize             The size of the Buffer in bytes. This must be a multiple of the
                                 intrinsic block size of the device.
  @param  Buffer                 A pointer to the destination buffer for the data. The caller
                                 is responsible for either having implicit or explicit ownership
                                 of the buffer.

  @retval EFI_SUCCESS                Success
  @retval EFI_DEVICE_ERROR           Hardware Error
  @retval EFI_INVALID_PARAMETER      Parameter is error
  @retval EFI_NO_MEDIA               No media
  @retval EFI_MEDIA_CHANGED          Media Change
  @retval EFI_BAD_BUFFER_SIZE        Buffer size is bad
**/
EFI_STATUS
EFIAPI
MMCSDBlockReadBlocks (
    IN  EFI_BLOCK_IO_PROTOCOL   *This,
    IN  UINT32                  MediaId,
    IN  EFI_LBA                 LBA,
    IN  UINTN                   BufferSize,
    OUT VOID                    *Buffer
)
{
    EFI_STATUS                  Status;
    UINT32                      Address;
    CARD_DATA                   *CardData;
    EFI_SD_HOST_IO_PROTOCOL     *SDHostIo;
    UINT32                      RemainingLength;
    UINT32                      TransferLength;
    UINT8                       *BufferPointer;
    BOOLEAN                     SectorAddressing;
    UINTN                       TotalBlock;

    DEBUG((EFI_D_INFO, "Read(LBA=%08lx, Buffer=%08x, Size=%08x)\n", LBA, Buffer, BufferSize));
    Status   = EFI_SUCCESS;
    CardData  = CARD_DATA_FROM_THIS(This);
    SDHostIo = CardData->SDHostIo;
    if (MediaId != CardData->BlockIoMedia.MediaId) {
        return EFI_MEDIA_CHANGED;
    }

    if (ModU64x32 (BufferSize,CardData->BlockIoMedia.BlockSize) != 0) {
        return EFI_BAD_BUFFER_SIZE;
    }
    if ((CardData->CardType == SDMemoryCard2High) || (CardData->CardType == MMCCardHighCap)) {
        SectorAddressing = TRUE;
    } else {
        SectorAddressing = FALSE;
    }
    if (SectorAddressing) {
        //
        //Block Address
        //
        Address = (UINT32)DivU64x32 (MultU64x32 (LBA, CardData->BlockIoMedia.BlockSize), 512);
    } else {
        //
        //Byte Address
        //
        Address  = (UINT32)MultU64x32 (LBA, CardData->BlockIoMedia.BlockSize);
    }
    TotalBlock = (UINTN) DivU64x32 (BufferSize, CardData->BlockIoMedia.BlockSize);
    if (LBA + TotalBlock > CardData->BlockIoMedia.LastBlock + 1) {
        return EFI_INVALID_PARAMETER;
    }


    if (!Buffer) {
        Status = EFI_INVALID_PARAMETER;
        DEBUG ((EFI_D_ERROR, "MMCSDBlockReadBlocks:Invalid parameter \r\n"));
        goto Done;
    }

    if ((BufferSize % CardData->BlockIoMedia.BlockSize) != 0) {
        Status = EFI_BAD_BUFFER_SIZE;
        DEBUG ((EFI_D_ERROR, "MMCSDBlockReadBlocks: Bad buffer size \r\n"));
        goto Done;
    }

    if (BufferSize == 0) {
        Status = EFI_SUCCESS;
        goto Done;
    }




    BufferPointer   = Buffer;
    RemainingLength = (UINT32)BufferSize;

    while (RemainingLength > 0) {
        if ((BufferSize > CardData->BlockIoMedia.BlockSize)) {
            if (RemainingLength > SDHostIo->HostCapability.BoundarySize) {
                TransferLength = SDHostIo->HostCapability.BoundarySize;
            } else {
                TransferLength = RemainingLength;
            }

            if (CardData->CardType == MMCCard || CardData->CardType == MMCCardHighCap) {
                if (!(CardData->ExtCSDRegister.CARD_TYPE & (BIT2 | BIT3))) {
                    Status = SendCommand (
                                 CardData,
                                 SET_BLOCKLEN,
                                 CardData->BlockIoMedia.BlockSize,
                                 NoData,
                                 NULL,
                                 0,
                                 ResponseR1,
                                 TIMEOUT_COMMAND,
                                 (UINT32*)&(CardData->CardStatus)
                             );
                    if (EFI_ERROR (Status)) {
                        break;
                    }
                }
                Status = SendCommand (
                             CardData,
                             SET_BLOCK_COUNT,
                             TransferLength / CardData->BlockIoMedia.BlockSize,
                             NoData,
                             NULL,
                             0,
                             ResponseR1,
                             TIMEOUT_COMMAND,
                             (UINT32*)&(CardData->CardStatus)
                         );
                if (EFI_ERROR (Status)) {
                    break;
                }
            }
            Status = SendCommand (
                         CardData,
                         READ_MULTIPLE_BLOCK,
                         Address,
                         InData,
                         CardData->AlignedBuffer,
                         TransferLength,
                         ResponseR1,
                         TIMEOUT_DATA,
                         (UINT32*)&(CardData->CardStatus)
                     );

            if (EFI_ERROR (Status)) {
                DEBUG ((EFI_D_ERROR, "MMCSDBlockReadBlocks: READ_MULTIPLE_BLOCK -> Fail\n"));
                break;
            }
        } else {
            if (RemainingLength > CardData->BlockIoMedia.BlockSize) {
                TransferLength = CardData->BlockIoMedia.BlockSize;
            } else {
                TransferLength = RemainingLength;
            }

            Status = SendCommand (
                         CardData,
                         READ_SINGLE_BLOCK,
                         Address,
                         InData,
                         CardData->AlignedBuffer,
                         (UINT32)TransferLength,
                         ResponseR1,
                         TIMEOUT_DATA,
                         (UINT32*)&(CardData->CardStatus)
                     );
            if (EFI_ERROR (Status)) {
                DEBUG ((EFI_D_ERROR, "MMCSDBlockReadBlocks: READ_SINGLE_BLOCK -> Fail\n"));
                break;
            }
        }
        CopyMem (BufferPointer, CardData->AlignedBuffer, TransferLength);

        if (SectorAddressing) {
            //
            //Block Address
            //
            Address += TransferLength / 512;
        } else {
            //
            //Byte Address
            //
            Address += TransferLength;
        }
        BufferPointer   += TransferLength;
        RemainingLength -= TransferLength;
    }


    if (EFI_ERROR (Status)) {
        if ((CardData->CardType == SDMemoryCard) ||
                (CardData->CardType == SDMemoryCard2)||
                (CardData->CardType == SDMemoryCard2High)) {
            SendCommand (
                CardData,
                STOP_TRANSMISSION,
                0,
                NoData,
                NULL,
                0,
                ResponseR1b,
                TIMEOUT_COMMAND,
                (UINT32*)&(CardData->CardStatus)
            );
        } else {
            SendCommand (
                CardData,
                STOP_TRANSMISSION,
                0,
                NoData,
                NULL,
                0,
                ResponseR1,
                TIMEOUT_COMMAND,
                (UINT32*)&(CardData->CardStatus)
            );
        }

    }


Done:
    DEBUG((EFI_D_INFO, "MMCSDBlockReadBlocks: Status = %r\n", Status));
    return Status;
}
예제 #2
0
파일: VirtioBlk.c 프로젝트: shijunjing/edk2
STATIC
EFI_STATUS
EFIAPI
VirtioBlkInit (
  IN OUT VBLK_DEV *Dev
  )
{
  UINT8      NextDevStat;
  EFI_STATUS Status;

  UINT64     Features;
  UINT64     NumSectors;
  UINT32     BlockSize;
  UINT8      PhysicalBlockExp;
  UINT8      AlignmentOffset;
  UINT32     OptIoSize;
  UINT16     QueueSize;
  UINT64     RingBaseShift;

  PhysicalBlockExp = 0;
  AlignmentOffset = 0;
  OptIoSize = 0;

  //
  // Execute virtio-0.9.5, 2.2.1 Device Initialization Sequence.
  //
  NextDevStat = 0;             // step 1 -- reset device
  Status = Dev->VirtIo->SetDeviceStatus (Dev->VirtIo, NextDevStat);
  if (EFI_ERROR (Status)) {
    goto Failed;
  }

  NextDevStat |= VSTAT_ACK;    // step 2 -- acknowledge device presence
  Status = Dev->VirtIo->SetDeviceStatus (Dev->VirtIo, NextDevStat);
  if (EFI_ERROR (Status)) {
    goto Failed;
  }

  NextDevStat |= VSTAT_DRIVER; // step 3 -- we know how to drive it
  Status = Dev->VirtIo->SetDeviceStatus (Dev->VirtIo, NextDevStat);
  if (EFI_ERROR (Status)) {
    goto Failed;
  }

  //
  // Set Page Size - MMIO VirtIo Specific
  //
  Status = Dev->VirtIo->SetPageSize (Dev->VirtIo, EFI_PAGE_SIZE);
  if (EFI_ERROR (Status)) {
    goto Failed;
  }

  //
  // step 4a -- retrieve and validate features
  //
  Status = Dev->VirtIo->GetDeviceFeatures (Dev->VirtIo, &Features);
  if (EFI_ERROR (Status)) {
    goto Failed;
  }

  Status = VIRTIO_CFG_READ (Dev, Capacity, &NumSectors);
  if (EFI_ERROR (Status)) {
    goto Failed;
  }
  if (NumSectors == 0) {
    Status = EFI_UNSUPPORTED;
    goto Failed;
  }

  if (Features & VIRTIO_BLK_F_BLK_SIZE) {
    Status = VIRTIO_CFG_READ (Dev, BlkSize, &BlockSize);
    if (EFI_ERROR (Status)) {
      goto Failed;
    }
    if (BlockSize == 0 || BlockSize % 512 != 0 ||
        ModU64x32 (NumSectors, BlockSize / 512) != 0) {
      //
      // We can only handle a logical block consisting of whole sectors,
      // and only a disk composed of whole logical blocks.
      //
      Status = EFI_UNSUPPORTED;
      goto Failed;
    }
  }
  else {
    BlockSize = 512;
  }

  if (Features & VIRTIO_BLK_F_TOPOLOGY) {
    Status = VIRTIO_CFG_READ (Dev, Topology.PhysicalBlockExp,
               &PhysicalBlockExp);
    if (EFI_ERROR (Status)) {
      goto Failed;
    }
    if (PhysicalBlockExp >= 32) {
      Status = EFI_UNSUPPORTED;
      goto Failed;
    }

    Status = VIRTIO_CFG_READ (Dev, Topology.AlignmentOffset, &AlignmentOffset);
    if (EFI_ERROR (Status)) {
      goto Failed;
    }

    Status = VIRTIO_CFG_READ (Dev, Topology.OptIoSize, &OptIoSize);
    if (EFI_ERROR (Status)) {
      goto Failed;
    }
  }

  Features &= VIRTIO_BLK_F_BLK_SIZE | VIRTIO_BLK_F_TOPOLOGY | VIRTIO_BLK_F_RO |
              VIRTIO_BLK_F_FLUSH | VIRTIO_F_VERSION_1 |
              VIRTIO_F_IOMMU_PLATFORM;

  //
  // In virtio-1.0, feature negotiation is expected to complete before queue
  // discovery, and the device can also reject the selected set of features.
  //
  if (Dev->VirtIo->Revision >= VIRTIO_SPEC_REVISION (1, 0, 0)) {
    Status = Virtio10WriteFeatures (Dev->VirtIo, Features, &NextDevStat);
    if (EFI_ERROR (Status)) {
      goto Failed;
    }
  }

  //
  // step 4b -- allocate virtqueue
  //
  Status = Dev->VirtIo->SetQueueSel (Dev->VirtIo, 0);
  if (EFI_ERROR (Status)) {
    goto Failed;
  }
  Status = Dev->VirtIo->GetQueueNumMax (Dev->VirtIo, &QueueSize);
  if (EFI_ERROR (Status)) {
    goto Failed;
  }
  if (QueueSize < 3) { // SynchronousRequest() uses at most three descriptors
    Status = EFI_UNSUPPORTED;
    goto Failed;
  }

  Status = VirtioRingInit (Dev->VirtIo, QueueSize, &Dev->Ring);
  if (EFI_ERROR (Status)) {
    goto Failed;
  }

  //
  // If anything fails from here on, we must release the ring resources
  //
  Status = VirtioRingMap (
             Dev->VirtIo,
             &Dev->Ring,
             &RingBaseShift,
             &Dev->RingMap
             );
  if (EFI_ERROR (Status)) {
    goto ReleaseQueue;
  }

  //
  // Additional steps for MMIO: align the queue appropriately, and set the
  // size. If anything fails from here on, we must unmap the ring resources.
  //
  Status = Dev->VirtIo->SetQueueNum (Dev->VirtIo, QueueSize);
  if (EFI_ERROR (Status)) {
    goto UnmapQueue;
  }

  Status = Dev->VirtIo->SetQueueAlign (Dev->VirtIo, EFI_PAGE_SIZE);
  if (EFI_ERROR (Status)) {
    goto UnmapQueue;
  }

  //
  // step 4c -- Report GPFN (guest-physical frame number) of queue.
  //
  Status = Dev->VirtIo->SetQueueAddress (
                          Dev->VirtIo,
                          &Dev->Ring,
                          RingBaseShift
                          );
  if (EFI_ERROR (Status)) {
    goto UnmapQueue;
  }


  //
  // step 5 -- Report understood features.
  //
  if (Dev->VirtIo->Revision < VIRTIO_SPEC_REVISION (1, 0, 0)) {
    Features &= ~(UINT64)(VIRTIO_F_VERSION_1 | VIRTIO_F_IOMMU_PLATFORM);
    Status = Dev->VirtIo->SetGuestFeatures (Dev->VirtIo, Features);
    if (EFI_ERROR (Status)) {
      goto UnmapQueue;
    }
  }

  //
  // step 6 -- initialization complete
  //
  NextDevStat |= VSTAT_DRIVER_OK;
  Status = Dev->VirtIo->SetDeviceStatus (Dev->VirtIo, NextDevStat);
  if (EFI_ERROR (Status)) {
    goto UnmapQueue;
  }

  //
  // Populate the exported interface's attributes; see UEFI spec v2.4, 12.9 EFI
  // Block I/O Protocol.
  //
  Dev->BlockIo.Revision              = 0;
  Dev->BlockIo.Media                 = &Dev->BlockIoMedia;
  Dev->BlockIo.Reset                 = &VirtioBlkReset;
  Dev->BlockIo.ReadBlocks            = &VirtioBlkReadBlocks;
  Dev->BlockIo.WriteBlocks           = &VirtioBlkWriteBlocks;
  Dev->BlockIo.FlushBlocks           = &VirtioBlkFlushBlocks;
  Dev->BlockIoMedia.MediaId          = 0;
  Dev->BlockIoMedia.RemovableMedia   = FALSE;
  Dev->BlockIoMedia.MediaPresent     = TRUE;
  Dev->BlockIoMedia.LogicalPartition = FALSE;
  Dev->BlockIoMedia.ReadOnly         = (BOOLEAN) ((Features & VIRTIO_BLK_F_RO) != 0);
  Dev->BlockIoMedia.WriteCaching     = (BOOLEAN) ((Features & VIRTIO_BLK_F_FLUSH) != 0);
  Dev->BlockIoMedia.BlockSize        = BlockSize;
  Dev->BlockIoMedia.IoAlign          = 0;
  Dev->BlockIoMedia.LastBlock        = DivU64x32 (NumSectors,
                                         BlockSize / 512) - 1;

  DEBUG ((DEBUG_INFO, "%a: LbaSize=0x%x[B] NumBlocks=0x%Lx[Lba]\n",
    __FUNCTION__, Dev->BlockIoMedia.BlockSize,
    Dev->BlockIoMedia.LastBlock + 1));

  if (Features & VIRTIO_BLK_F_TOPOLOGY) {
    Dev->BlockIo.Revision = EFI_BLOCK_IO_PROTOCOL_REVISION3;

    Dev->BlockIoMedia.LowestAlignedLba = AlignmentOffset;
    Dev->BlockIoMedia.LogicalBlocksPerPhysicalBlock = 1u << PhysicalBlockExp;
    Dev->BlockIoMedia.OptimalTransferLengthGranularity = OptIoSize;

    DEBUG ((DEBUG_INFO, "%a: FirstAligned=0x%Lx[Lba] PhysBlkSize=0x%x[Lba]\n",
      __FUNCTION__, Dev->BlockIoMedia.LowestAlignedLba,
      Dev->BlockIoMedia.LogicalBlocksPerPhysicalBlock));
    DEBUG ((DEBUG_INFO, "%a: OptimalTransferLengthGranularity=0x%x[Lba]\n",
      __FUNCTION__, Dev->BlockIoMedia.OptimalTransferLengthGranularity));
  }
  return EFI_SUCCESS;

UnmapQueue:
  Dev->VirtIo->UnmapSharedBuffer (Dev->VirtIo, Dev->RingMap);

ReleaseQueue:
  VirtioRingUninit (Dev->VirtIo, &Dev->Ring);

Failed:
  //
  // Notify the host about our failure to setup: virtio-0.9.5, 2.2.2.1 Device
  // Status. VirtIo access failure here should not mask the original error.
  //
  NextDevStat |= VSTAT_FAILED;
  Dev->VirtIo->SetDeviceStatus (Dev->VirtIo, NextDevStat);

  return Status; // reached only via Failed above
}
예제 #3
0
파일: BlockIo.c 프로젝트: etiago/vbox
/**
  Reads the requested number of blocks from the device.

  This function implements EFI_BLOCK_IO_PROTOCOL.ReadBlocks(). 
  It reads the requested number of blocks from the device.
  All the blocks are read, or an error is returned.

  @param  This                   Indicates a pointer to the calling context.
  @param  ReadData               If TRUE then read data.  If FALSE then write data.
  @param  MediaId                The media ID that the read request is for.
  @param  Lba                    The starting logical block address to read from on the device.
  @param  BufferSize             The size of the Buffer in bytes.
                                 This must be a multiple of the intrinsic block size of the device.
  @param  Buffer                 A pointer to the destination buffer for the data. The caller is
                                 responsible for either having implicit or explicit ownership of the buffer.

  @retval EFI_SUCCESS            The data was read correctly from the device.
  @retval EFI_DEVICE_ERROR       The device reported an error while attempting to perform the read operation.
  @retval EFI_NO_MEDIA           There is no media in the device.
  @retval EFI_MEDIA_CHANGED      The MediaId is not for the current media.
  @retval EFI_BAD_BUFFER_SIZE    The BufferSize parameter is not a multiple of the intrinsic block size of the device.
  @retval EFI_INVALID_PARAMETER  The read request contains LBAs that are not valid,
                                 or the buffer is not on proper alignment.

**/
EFI_STATUS
EFIAPI
ReadOrWriteBlocks (
  IN EFI_BLOCK_IO_PROTOCOL    *This,
  IN BOOLEAN                  ReadData,
  IN UINT32                   MediaId,
  IN EFI_LBA                  Lba,
  IN UINTN                    BufferSize,
  OUT VOID                    *Buffer
  )
{
  EFI_STATUS                    Status;
  BLOCK_MMIO_TO_BLOCK_IO_DEVICE *Private;
  UINTN                         TotalBlock;
  EFI_BLOCK_IO_MEDIA            *Media;
  UINT64                        Address;
  UINTN                         Count;
  EFI_CPU_IO_PROTOCOL_IO_MEM    CpuAccessFunction;

  //
  // First, validate the parameters
  //
  if ((Buffer == NULL) || (BufferSize == 0)) {
    return EFI_INVALID_PARAMETER;
  }

  //
  // Get private data structure
  //
  Private = PRIVATE_FROM_BLOCK_IO (This);
  Media   = Private->BlockMmio->Media;

  //
  // BufferSize must be a multiple of the intrinsic block size of the device.
  //
  if (ModU64x32 (BufferSize, Media->BlockSize) != 0) {
    return EFI_BAD_BUFFER_SIZE;
  }

  TotalBlock = (UINTN) DivU64x32 (BufferSize, Media->BlockSize);

  //
  // Make sure the range to read is valid.
  //
  if (Lba + TotalBlock - 1 > Media->LastBlock) {
    return EFI_INVALID_PARAMETER;
  }

  if (!(Media->MediaPresent)) {
    return EFI_NO_MEDIA;
  }

  if (MediaId != Media->MediaId) {
    return EFI_MEDIA_CHANGED;
  }

  Address = Private->BlockMmio->BaseAddress;
  Address += MultU64x32 (Lba, Media->BlockSize);

  Count = BufferSize >> 3;

  if (ReadData) {
    CpuAccessFunction = Private->CpuIo->Mem.Read;
  } else {
    CpuAccessFunction = Private->CpuIo->Mem.Write;
  }

  Status = (CpuAccessFunction) (
             Private->CpuIo,
             EfiCpuIoWidthUint64,
             Address,
             Count,
             Buffer
             );

  return Status;
}