|
[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
|
![]() |
Lists.xenproject.org is hosted with RackSpace, monitoring our |