[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [Xen-devel] [PATCH RFC 18/18] OvmfPkg/XenPvBlkDxe: Add BlockIo.



On Wed, Jul 16, 2014 at 04:15:47PM +0100, Anthony PERARD wrote:
> Install the BlockIo protocol.
> 
> Contributed-under: TianoCore Contribution Agreement 1.0
> Signed-off-by: Anthony PERARD <anthony.perard@xxxxxxxxxx>
> ---
>  OvmfPkg/XenPvBlkDxe/BlockIo.c       | 256 
> ++++++++++++++++++++++++++++++++++++
>  OvmfPkg/XenPvBlkDxe/BlockIo.h       | 109 +++++++++++++++
>  OvmfPkg/XenPvBlkDxe/XenPvBlkDxe.c   |  59 +++++++++
>  OvmfPkg/XenPvBlkDxe/XenPvBlkDxe.h   |   1 +
>  OvmfPkg/XenPvBlkDxe/XenPvBlkDxe.inf |   2 +
>  5 files changed, 427 insertions(+)
>  create mode 100644 OvmfPkg/XenPvBlkDxe/BlockIo.c
>  create mode 100644 OvmfPkg/XenPvBlkDxe/BlockIo.h
> 
> diff --git a/OvmfPkg/XenPvBlkDxe/BlockIo.c b/OvmfPkg/XenPvBlkDxe/BlockIo.c
> new file mode 100644
> index 0000000..4ac2411
> --- /dev/null
> +++ b/OvmfPkg/XenPvBlkDxe/BlockIo.c
> @@ -0,0 +1,256 @@
> +
> +/** @file
> +  TODO: Brief Description of UEFI Driver XenPvBlkDxe
> +
> +  TODO: Detailed Description of UEFI Driver XenPvBlkDxe
> +
> +  TODO: Copyright for UEFI Driver XenPvBlkDxe
> +
> +  TODO: License for UEFI Driver XenPvBlkDxe
> +
> +**/
> +
> +#include "XenPvBlkDxe.h"
> +
> +#include "BlockFront.h"
> +
> +///
> +/// Block I/O Media structure
> +///
> +GLOBAL_REMOVE_IF_UNREFERENCED
> +EFI_BLOCK_IO_MEDIA  gXenPvBlkDxeBlockIoMedia = {
> +  0,      // MediaId
> +  FALSE,  // RemovableMedia
> +  FALSE,  // MediaPresent
> +  FALSE,  // LogicalPartition
> +  TRUE,   // ReadOnly
> +  FALSE,  // WriteCaching
> +  512,    // BlockSize
> +  512,    // IoAlign
> +  0,      // LastBlock
> +  0,      // LowestAlignedLba
> +  0,      // LogicalBlocksPerPhysicalBlock
> +  0       // OptimalTransferLengthGranularity
> +};
> +
> +///
> +/// Block I/O Protocol instance
> +///
> +GLOBAL_REMOVE_IF_UNREFERENCED
> +EFI_BLOCK_IO_PROTOCOL  gXenPvBlkDxeBlockIo = {
> +  EFI_BLOCK_IO_PROTOCOL_REVISION3,             // Revision
> +  &gXenPvBlkDxeBlockIoMedia,                // Media
> +  (EFI_BLOCK_RESET)XenPvBlkDxeBlockIoReset, // Reset
> +  XenPvBlkDxeBlockIoReadBlocks,             // ReadBlocks
> +  XenPvBlkDxeBlockIoWriteBlocks,            // WriteBlocks
> +  XenPvBlkDxeBlockIoFlushBlocks             // FlushBlocks
> +};
> +
> +
> +
> +
> +STATIC
> +EFI_STATUS
> +XenPvBlkDxeBlockIoReadWriteBlocks (
> +  IN     EFI_BLOCK_IO_PROTOCOL  *This,
> +  IN     UINT32                 MediaId,
> +  IN     EFI_LBA                Lba,
> +  IN     UINTN                  BufferSize,
> +  IN OUT VOID                   *Buffer,
> +  IN     BOOLEAN                IsWrite
> +  )
> +{
> +  XEN_BLOCK_FRONT_IO IoData;
> +  EFI_BLOCK_IO_MEDIA *Media;
> +  UINTN NextOffset;
> +
> +  if (Buffer == NULL) {
> +    DEBUG ((EFI_D_ERROR, "%a %d, buffer null\n", __func__, __LINE__));

Heheh.

> +    return EFI_INVALID_PARAMETER;
> +  }
> +  if (BufferSize == 0) {
> +    return EFI_SUCCESS;
> +  }
> +
> +  Media = This->Media;
> +
> +  if (BufferSize % Media->BlockSize != 0) {
> +    DEBUG ((EFI_D_ERROR, "%a %d, bad buffer size\n", __func__, __LINE__));
> +    return EFI_BAD_BUFFER_SIZE;
> +  }
> +
> +  if (Lba > Media->LastBlock ||
> +      (BufferSize / Media->BlockSize) - 1 > Media->LastBlock - Lba) {
> +    DEBUG ((EFI_D_ERROR, "%a %d, read too large\n", __func__, __LINE__));
> +    return EFI_INVALID_PARAMETER;
> +  }
> +
> +  if (IsWrite && Media->ReadOnly) {
> +    DEBUG ((EFI_D_ERROR, "%a %d, read only\n", __func__, __LINE__));
> +    return EFI_WRITE_PROTECTED;
> +  }
> +
> +  if ((Media->IoAlign > 1) && (UINTN)Buffer & (Media->IoAlign - 1)) {
> +    // This happen often when using grub2
> +    VOID *NewBuffer;
> +    EFI_STATUS Status;
> +
> +    /* Try again with a properly aligned buffer. */
> +    NewBuffer = AllocateAlignedPages((BufferSize + EFI_PAGE_SIZE) / 
> EFI_PAGE_SIZE,
> +                                     Media->IoAlign);
> +    if (!IsWrite) {
> +      Status = XenPvBlkDxeBlockIoReadBlocks (This, MediaId,
> +                                             Lba, BufferSize, NewBuffer);
> +      CopyMem (Buffer, NewBuffer, BufferSize);
> +    } else {
> +      CopyMem (NewBuffer, Buffer, BufferSize);
> +      Status = XenPvBlkDxeBlockIoWriteBlocks (This, MediaId,
> +                                              Lba, BufferSize, NewBuffer);
> +    }
> +    FreeAlignedPages (NewBuffer, (BufferSize + EFI_PAGE_SIZE) / 
> EFI_PAGE_SIZE);
> +    return Status;
> +  }
> +
> +
> +  // XXX Check MediaId
> +
> +  IoData.Dev = XEN_BLOCK_FRONT_FROM_BLOCK_IO (This);
> +  IoData.Offset = Lba * Media->BlockSize;
> +  IoData.Callback = NULL;
> +  IoData.Data = NULL;
> +  IoData.Size = BufferSize;
> +  IoData.Buffer = Buffer;
> +
> +  NextOffset = Lba * Media->BlockSize;

Or just = IoData.Offset ?

> +  while (BufferSize > 0) {
> +    // This should work if every Buffer is page aligned
> +    // but block accept sector aligned, so FIXME

Isn't the work-around for GRUB2 above doing this?

> +    IoData.Size = MIN(EFI_PAGE_SIZE * 8,//BLKIF_MAX_SEGMENTS_PER_REQUEST,
> +                           BufferSize);

Why 8 ?

> +    IoData.Buffer = Buffer;
> +    IoData.Offset = NextOffset;
> +    BufferSize -= IoData.Size;
> +    Buffer = (VOID*) ((UINTN) Buffer + IoData.Size);
> +    NextOffset += IoData.Size;
> +    XenPvBlockIo (&IoData, IsWrite);
> +    if (!IoData.Data) {

Well that wouldn't be possible as the XenPvBlockIo loops forever until that
is done.

However, you should probably have a comment here:

/* XXX If we move to a different mechanism for CallBack this might
   go away */

> +      DEBUG ((EFI_D_ERROR, "%a %d, XenPvBlockIo no data...\n", __func__, 
> __LINE__));
> +      return EFI_DEVICE_ERROR;
> +    }
> +  }
> +  return EFI_SUCCESS;
> +}
> +
> +
> +/**
> +  Read BufferSize bytes from Lba into Buffer.
> +
> +  @param  This       Indicates a pointer to the calling context.
> +  @param  MediaId    Id of the media, changes every time the media is 
> replaced.
> +  @param  Lba        The starting Logical Block Address to read from
> +  @param  BufferSize Size of Buffer, must be a multiple of device block size.
> +  @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 
> performing the read.
> +  @retval EFI_NO_MEDIA          There is no media in the device.
> +  @retval EFI_MEDIA_CHANGED     The MediaId does not matched the current 
> device.
> +  @retval EFI_BAD_BUFFER_SIZE   The Buffer was not a multiple of the 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
> +XenPvBlkDxeBlockIoReadBlocks (
> +  IN  EFI_BLOCK_IO_PROTOCOL         *This,
> +  IN  UINT32                        MediaId,
> +  IN  EFI_LBA                       Lba,
> +  IN  UINTN                         BufferSize,
> +  OUT VOID                          *Buffer
> +  )
> +{
> +  return XenPvBlkDxeBlockIoReadWriteBlocks (This,
> +      MediaId, Lba, BufferSize, Buffer, FALSE);
> +}
> +
> +/**
> +  Write BufferSize bytes from Lba into Buffer.
> +
> +  @param  This       Indicates a pointer to the calling context.
> +  @param  MediaId    The media ID that the write request is for.
> +  @param  Lba        The starting logical block address to be written. The 
> caller is
> +                     responsible for writing to only legitimate locations.
> +  @param  BufferSize Size of Buffer, must be a multiple of device block size.
> +  @param  Buffer     A pointer to the source buffer for the data.
> +
> +  @retval EFI_SUCCESS           The data was written correctly to the device.
> +  @retval EFI_WRITE_PROTECTED   The device can not be written to.
> +  @retval EFI_DEVICE_ERROR      The device reported an error while 
> performing the write.
> +  @retval EFI_NO_MEDIA          There is no media in the device.
> +  @retval EFI_MEDIA_CHNAGED     The MediaId does not matched the current 
> device.
> +  @retval EFI_BAD_BUFFER_SIZE   The Buffer was not a multiple of the block 
> size of the device.
> +  @retval EFI_INVALID_PARAMETER The write request contains LBAs that are not 
> valid,
> +                                or the buffer is not on proper alignment.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +XenPvBlkDxeBlockIoWriteBlocks (
> +  IN EFI_BLOCK_IO_PROTOCOL          *This,
> +  IN UINT32                         MediaId,
> +  IN EFI_LBA                        Lba,
> +  IN UINTN                          BufferSize,
> +  IN VOID                           *Buffer
> +  )
> +{
> +  return XenPvBlkDxeBlockIoReadWriteBlocks (This,
> +      MediaId, Lba, BufferSize, Buffer, TRUE);
> +}
> +
> +/**
> +  Flush the Block Device.
> +
> +  @param  This              Indicates a pointer to the calling context.
> +
> +  @retval EFI_SUCCESS       All outstanding data was written to the device
> +  @retval EFI_DEVICE_ERROR  The device reported an error while writting back 
> the data
> +  @retval EFI_NO_MEDIA      There is no media in the device.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +XenPvBlkDxeBlockIoFlushBlocks (
> +  IN EFI_BLOCK_IO_PROTOCOL  *This
> +  )
> +{
> +  XenPvBlockSync (XEN_BLOCK_FRONT_FROM_BLOCK_IO (This));
> +  return EFI_SUCCESS;
> +}
> +
> +/**
> +  Reset the block device hardware.
> +
> +  @param[in]  This                 Indicates a pointer to the calling 
> context.
> +  @param[in]  ExtendedVerification Indicates that the driver may perform a 
> more
> +                                   exhausive verfication operation of the 
> device
> +                                   during reset.
> +
> +  @retval EFI_SUCCESS          The device was reset.
> +  @retval EFI_DEVICE_ERROR     The device is not functioning properly and 
> could
> +                               not be reset.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +XenPvBlkDxeBlockIoReset (
> +  IN EFI_BLOCK_IO2_PROTOCOL  *This,
> +  IN BOOLEAN                 ExtendedVerification
> +  )
> +{
> +  // Is there anything to do ?
> +  // since initialisation is done in Start (driver binding)

Won't we leak memory? Or will it after an Reset do Stop, then Start?


> +  DEBUG ((EFI_D_INFO, "%a %d\n", __func__, __LINE__));
> +  return EFI_SUCCESS;
> +}
> diff --git a/OvmfPkg/XenPvBlkDxe/BlockIo.h b/OvmfPkg/XenPvBlkDxe/BlockIo.h
> new file mode 100644
> index 0000000..ec0fe2b
> --- /dev/null
> +++ b/OvmfPkg/XenPvBlkDxe/BlockIo.h
> @@ -0,0 +1,109 @@
> +
> +/** @file
> +  TODO: Brief Description of UEFI Driver XenPvBlkDxe
> +
> +  TODO: Detailed Description of UEFI Driver XenPvBlkDxe
> +
> +  TODO: Copyright for UEFI Driver XenPvBlkDxe
> +
> +  TODO: License for UEFI Driver XenPvBlkDxe
> +
> +**/
> +
> +/**
> +  Read BufferSize bytes from Lba into Buffer.
> +
> +  @param  This       Indicates a pointer to the calling context.
> +  @param  MediaId    Id of the media, changes every time the media is 
> replaced.
> +  @param  Lba        The starting Logical Block Address to read from
> +  @param  BufferSize Size of Buffer, must be a multiple of device block size.
> +  @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 
> performing the read.
> +  @retval EFI_NO_MEDIA          There is no media in the device.
> +  @retval EFI_MEDIA_CHANGED     The MediaId does not matched the current 
> device.
> +  @retval EFI_BAD_BUFFER_SIZE   The Buffer was not a multiple of the 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
> +XenPvBlkDxeBlockIoReadBlocks (
> +  IN EFI_BLOCK_IO_PROTOCOL          *This,
> +  IN UINT32                         MediaId,
> +  IN EFI_LBA                        Lba,
> +  IN UINTN                          BufferSize,
> +  OUT VOID                          *Buffer
> +  );
> +
> +/**
> +  Write BufferSize bytes from Lba into Buffer.
> +
> +  @param  This       Indicates a pointer to the calling context.
> +  @param  MediaId    The media ID that the write request is for.
> +  @param  Lba        The starting logical block address to be written. The 
> caller is
> +                     responsible for writing to only legitimate locations.
> +  @param  BufferSize Size of Buffer, must be a multiple of device block size.
> +  @param  Buffer     A pointer to the source buffer for the data.
> +
> +  @retval EFI_SUCCESS           The data was written correctly to the device.
> +  @retval EFI_WRITE_PROTECTED   The device can not be written to.
> +  @retval EFI_DEVICE_ERROR      The device reported an error while 
> performing the write.
> +  @retval EFI_NO_MEDIA          There is no media in the device.
> +  @retval EFI_MEDIA_CHNAGED     The MediaId does not matched the current 
> device.
> +  @retval EFI_BAD_BUFFER_SIZE   The Buffer was not a multiple of the block 
> size of the device.
> +  @retval EFI_INVALID_PARAMETER The write request contains LBAs that are not 
> valid,
> +                                or the buffer is not on proper alignment.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +XenPvBlkDxeBlockIoWriteBlocks (
> +  IN EFI_BLOCK_IO_PROTOCOL          *This,
> +  IN UINT32                         MediaId,
> +  IN EFI_LBA                        Lba,
> +  IN UINTN                          BufferSize,
> +  IN VOID                           *Buffer
> +  );
> +
> +/**
> +  Flush the Block Device.
> +
> +  @param  This              Indicates a pointer to the calling context.
> +
> +  @retval EFI_SUCCESS       All outstanding data was written to the device
> +  @retval EFI_DEVICE_ERROR  The device reported an error while writting back 
> the data
> +  @retval EFI_NO_MEDIA      There is no media in the device.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +XenPvBlkDxeBlockIoFlushBlocks (
> +  IN EFI_BLOCK_IO_PROTOCOL  *This
> +  );
> +
> +/**
> +  Reset the block device hardware.
> +
> +  @param[in]  This                 Indicates a pointer to the calling 
> context.
> +  @param[in]  ExtendedVerification Indicates that the driver may perform a 
> more
> +                                   exhausive verfication operation of the 
> device
> +                                   during reset.
> +
> +  @retval EFI_SUCCESS          The device was reset.
> +  @retval EFI_DEVICE_ERROR     The device is not functioning properly and 
> could
> +                               not be reset.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +XenPvBlkDxeBlockIoReset (
> +  IN EFI_BLOCK_IO2_PROTOCOL  *This,
> +  IN BOOLEAN                 ExtendedVerification
> +  );
> +
> +extern EFI_BLOCK_IO_MEDIA  gXenPvBlkDxeBlockIoMedia;
> +extern EFI_BLOCK_IO_PROTOCOL  gXenPvBlkDxeBlockIo;
> diff --git a/OvmfPkg/XenPvBlkDxe/XenPvBlkDxe.c 
> b/OvmfPkg/XenPvBlkDxe/XenPvBlkDxe.c
> index 7ec7d60..3991e83 100644
> --- a/OvmfPkg/XenPvBlkDxe/XenPvBlkDxe.c
> +++ b/OvmfPkg/XenPvBlkDxe/XenPvBlkDxe.c
> @@ -266,6 +266,7 @@ XenPvBlkDxeDriverBindingStart (
>    EFI_STATUS Status;
>    XENBUS_PROTOCOL *XenbusIo;
>    XEN_BLOCK_FRONT_DEVICE *Dev;
> +  EFI_BLOCK_IO_MEDIA *Media;
>  
>    Status = gBS->OpenProtocol (
>                  ControllerHandle,
> @@ -284,6 +285,37 @@ XenPvBlkDxeDriverBindingStart (
>      return Status;
>    }
>  
> +  CopyMem (&Dev->BlockIo, &gXenPvBlkDxeBlockIo, sizeof 
> (EFI_BLOCK_IO_PROTOCOL));
> +  Media = AllocateCopyPool (sizeof (EFI_BLOCK_IO_MEDIA),
> +                            &gXenPvBlkDxeBlockIoMedia);
> +  if (Dev->MediaInfo.VDiskInfo & VDISK_REMOVABLE) {
> +    Media->RemovableMedia = TRUE;
> +  }
> +  Media->MediaPresent = TRUE;
> +  Media->ReadOnly = !Dev->MediaInfo.ReadWrite;
> +  if (Dev->MediaInfo.CdRom) {
> +    // If it's a cdrom, the blocksize value need to be 2048 for OVMF to
> +    // recognize it as a cdrom:
> +    //    MdeModulePkg/Universal/Disk/PartitionDxe/ElTorito.c
> +    Media->BlockSize = 2048;
> +  } else {
> +    Media->BlockSize = Dev->MediaInfo.SectorSize;
> +  }
> +  Media->LastBlock = Dev->MediaInfo.Sectors - 1;
> +  // XXX What about LowestAlignedLba, LogicalBlocksPerPhysicalBlock and 
> OptimalTransferLengthGranularity?

I think you can skip  LogicalBlocksPerPhysicalBlock and 
OptimalTransferLengthGranularity
as they are used for discard operations.

The LowestAlignedLba .. no idea.

> +  Dev->BlockIo.Media = Media;
> +
> +  Status = gBS->InstallMultipleProtocolInterfaces (
> +                    &ControllerHandle,
> +                    &gEfiBlockIoProtocolGuid, &Dev->BlockIo,
> +                    NULL
> +                    );
> +  if (EFI_ERROR (Status)) {
> +    // XXX: uninit everythings

 XenPvBlockFrontShutdown (Dev); ?
 FreePool(Media) ?

> +    DEBUG ((EFI_D_ERROR, "XenPvBlk: install protocol fail: %r\n", Status));
> +    return Status;
> +  }
> +
>    return EFI_SUCCESS;
>  }
>  
> @@ -322,6 +354,33 @@ XenPvBlkDxeDriverBindingStop (
>    IN EFI_HANDLE                   *ChildHandleBuffer OPTIONAL
>    )
>  {
> +  EFI_BLOCK_IO_PROTOCOL *BlockIo;
> +  XEN_BLOCK_FRONT_DEVICE *Dev;
> +  EFI_BLOCK_IO_MEDIA *Media;
> +  EFI_STATUS Status;
> +
> +  Status = gBS->OpenProtocol (
> +                  ControllerHandle, &gEfiBlockIoProtocolGuid,
> +                  (VOID **)&BlockIo,
> +                  This->DriverBindingHandle, ControllerHandle,
> +                  EFI_OPEN_PROTOCOL_GET_PROTOCOL
> +                  );
> +  if (EFI_ERROR (Status)) {
> +    return Status;
> +  }
> +
> +  Status = gBS->UninstallProtocolInterface (ControllerHandle,
> +                  &gEfiBlockIoProtocolGuid, BlockIo);
> +  if (EFI_ERROR (Status)) {
> +    return Status;
> +  }
> +
> +  Media = BlockIo->Media;
> +  Dev = XEN_BLOCK_FRONT_FROM_BLOCK_IO (BlockIo);
> +  XenPvBlockFrontShutdown (Dev);
> +
> +  FreePool (Media);
> +
>    gBS->CloseProtocol (ControllerHandle, &gXenbusProtocolGuid,
>           This->DriverBindingHandle, ControllerHandle);
>  
> diff --git a/OvmfPkg/XenPvBlkDxe/XenPvBlkDxe.h 
> b/OvmfPkg/XenPvBlkDxe/XenPvBlkDxe.h
> index 186d0ee..3120137 100644
> --- a/OvmfPkg/XenPvBlkDxe/XenPvBlkDxe.h
> +++ b/OvmfPkg/XenPvBlkDxe/XenPvBlkDxe.h
> @@ -76,6 +76,7 @@ extern EFI_COMPONENT_NAME_PROTOCOL  
> gXenPvBlkDxeComponentName;
>  //
>  #include "DriverBinding.h"
>  #include "ComponentName.h"
> +#include "BlockIo.h"
>  
>  
>  
> diff --git a/OvmfPkg/XenPvBlkDxe/XenPvBlkDxe.inf 
> b/OvmfPkg/XenPvBlkDxe/XenPvBlkDxe.inf
> index a43d006..b379020 100644
> --- a/OvmfPkg/XenPvBlkDxe/XenPvBlkDxe.inf
> +++ b/OvmfPkg/XenPvBlkDxe/XenPvBlkDxe.inf
> @@ -32,6 +32,8 @@
>    ComponentName.h
>    BlockFront.c
>    BlockFront.h
> +  BlockIo.c
> +  BlockIo.h
>  
>  
>  [LibraryClasses]
> -- 
> Anthony PERARD
> 
> 
> _______________________________________________
> Xen-devel mailing list
> Xen-devel@xxxxxxxxxxxxx
> http://lists.xen.org/xen-devel

_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxx
http://lists.xen.org/xen-devel


 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.