mirror of https://github.com/acidanthera/audk.git
OvmfPkg/XenPvBlkDxe: Add BlockIo.
Implement the BlockIo protocol. Change in V4: - Replace the license by the commonly used file header text. Change in V3: - assert(Media->BlockSize % 512 == 0) - Use Sector instead of Offset to issue IOs. Change in V2: - Remove blockIo2 headers. - Fix few comment. - file header, copyright - Rewrite few comment and error messages - No more callback - Improving block read/write, increase to the max size in one request (instead of only 8pages) - Fix lastblock when it's a cdrom - Do uninitialisation when fail to install fail - few comment - Licenses Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Anthony PERARD <anthony.perard@citrix.com> Reviewed-by: Jordan Justen <jordan.l.justen@intel.com> git-svn-id: https://svn.code.sf.net/p/edk2/code/trunk/edk2@16274 6f19259b-4bc3-4df7-8a09-765794883524
This commit is contained in:
parent
5cce852404
commit
5de8a35c62
|
@ -0,0 +1,274 @@
|
|||
/** @file
|
||||
BlockIo implementation for Xen PV Block driver.
|
||||
|
||||
This file is implementing the interface between the actual driver in
|
||||
BlockFront.c to the BlockIo protocol.
|
||||
|
||||
Copyright (C) 2014, Citrix Ltd.
|
||||
|
||||
This program and the accompanying materials
|
||||
are licensed and made available under the terms and conditions of the BSD License
|
||||
which accompanies this distribution. The full text of the license may be found at
|
||||
http://opensource.org/licenses/bsd-license.php
|
||||
|
||||
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
|
||||
|
||||
**/
|
||||
|
||||
#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, BlockFront does not support less than 512 bits-aligned.
|
||||
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
|
||||
XenPvBlkDxeBlockIoReset, // Reset
|
||||
XenPvBlkDxeBlockIoReadBlocks, // ReadBlocks
|
||||
XenPvBlkDxeBlockIoWriteBlocks, // WriteBlocks
|
||||
XenPvBlkDxeBlockIoFlushBlocks // FlushBlocks
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
Read/Write BufferSize bytes from Lba into Buffer.
|
||||
|
||||
This function is commun to XenPvBlkDxeBlockIoReadBlocks and
|
||||
XenPvBlkDxeBlockIoWriteBlocks.
|
||||
|
||||
@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/write to.
|
||||
@param BufferSize Size of Buffer, must be a multiple of device block size.
|
||||
@param Buffer A pointer to the destination/source buffer for the data.
|
||||
@param IsWrite Indicate if the operation is write or read.
|
||||
|
||||
@return See description of XenPvBlkDxeBlockIoReadBlocks and
|
||||
XenPvBlkDxeBlockIoWriteBlocks.
|
||||
**/
|
||||
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 = This->Media;
|
||||
UINTN Sector;
|
||||
EFI_STATUS Status;
|
||||
|
||||
if (Buffer == NULL) {
|
||||
return EFI_INVALID_PARAMETER;
|
||||
}
|
||||
if (BufferSize == 0) {
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
|
||||
if (BufferSize % Media->BlockSize != 0) {
|
||||
DEBUG ((EFI_D_ERROR, "XenPvBlkDxe: Bad buffer size: 0x%X\n", BufferSize));
|
||||
return EFI_BAD_BUFFER_SIZE;
|
||||
}
|
||||
|
||||
if (Lba > Media->LastBlock ||
|
||||
(BufferSize / Media->BlockSize) - 1 > Media->LastBlock - Lba) {
|
||||
DEBUG ((EFI_D_ERROR, "XenPvBlkDxe: %a with invalid LBA: 0x%LX, size: 0x%x\n",
|
||||
IsWrite ? "Write" : "Read", Lba, BufferSize));
|
||||
return EFI_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
if (IsWrite && Media->ReadOnly) {
|
||||
return EFI_WRITE_PROTECTED;
|
||||
}
|
||||
|
||||
if ((Media->IoAlign > 1) && (UINTN)Buffer & (Media->IoAlign - 1)) {
|
||||
//
|
||||
// Grub2 does not appear to respect IoAlign of 512, so reallocate the
|
||||
// buffer here.
|
||||
//
|
||||
VOID *NewBuffer;
|
||||
|
||||
//
|
||||
// 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;
|
||||
}
|
||||
|
||||
IoData.Dev = XEN_BLOCK_FRONT_FROM_BLOCK_IO (This);
|
||||
Sector = Lba * (Media->BlockSize / 512);
|
||||
|
||||
while (BufferSize > 0) {
|
||||
if (((UINTN)Buffer & EFI_PAGE_MASK) == 0) {
|
||||
IoData.Size = MIN (BLKIF_MAX_SEGMENTS_PER_REQUEST * EFI_PAGE_SIZE,
|
||||
BufferSize);
|
||||
} else {
|
||||
IoData.Size = MIN ((BLKIF_MAX_SEGMENTS_PER_REQUEST - 1) * EFI_PAGE_SIZE,
|
||||
BufferSize);
|
||||
}
|
||||
|
||||
IoData.Buffer = Buffer;
|
||||
IoData.Sector = Sector;
|
||||
BufferSize -= IoData.Size;
|
||||
Buffer = (VOID*) ((UINTN) Buffer + IoData.Size);
|
||||
Sector += IoData.Size / 512;
|
||||
Status = XenPvBlockIo (&IoData, IsWrite);
|
||||
if (EFI_ERROR (Status)) {
|
||||
DEBUG ((EFI_D_ERROR, "XenPvBlkDxe: Error durring %a operation.\n",
|
||||
IsWrite ? "write" : "read"));
|
||||
return Status;
|
||||
}
|
||||
}
|
||||
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 Not used.
|
||||
|
||||
@retval EFI_SUCCESS The device was reset.
|
||||
|
||||
**/
|
||||
EFI_STATUS
|
||||
EFIAPI
|
||||
XenPvBlkDxeBlockIoReset (
|
||||
IN EFI_BLOCK_IO_PROTOCOL *This,
|
||||
IN BOOLEAN ExtendedVerification
|
||||
)
|
||||
{
|
||||
//
|
||||
// Since the initialization of the devices is done, then the device is
|
||||
// working correctly.
|
||||
//
|
||||
return EFI_SUCCESS;
|
||||
}
|
|
@ -0,0 +1,108 @@
|
|||
/** @file
|
||||
BlockIo function declaration for Xen PV block driver.
|
||||
|
||||
Copyright (C) 2014, Citrix Ltd.
|
||||
|
||||
This program and the accompanying materials
|
||||
are licensed and made available under the terms and conditions of the BSD License
|
||||
which accompanies this distribution. The full text of the license may be found at
|
||||
http://opensource.org/licenses/bsd-license.php
|
||||
|
||||
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
|
||||
|
||||
**/
|
||||
|
||||
/**
|
||||
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 Not used.
|
||||
|
||||
@retval EFI_SUCCESS The device was reset.
|
||||
|
||||
**/
|
||||
EFI_STATUS
|
||||
EFIAPI
|
||||
XenPvBlkDxeBlockIoReset (
|
||||
IN EFI_BLOCK_IO_PROTOCOL *This,
|
||||
IN BOOLEAN ExtendedVerification
|
||||
);
|
||||
|
||||
extern EFI_BLOCK_IO_MEDIA gXenPvBlkDxeBlockIoMedia;
|
||||
extern EFI_BLOCK_IO_PROTOCOL gXenPvBlkDxeBlockIo;
|
|
@ -261,6 +261,7 @@ XenPvBlkDxeDriverBindingStart (
|
|||
EFI_STATUS Status;
|
||||
XENBUS_PROTOCOL *XenBusIo;
|
||||
XEN_BLOCK_FRONT_DEVICE *Dev;
|
||||
EFI_BLOCK_IO_MEDIA *Media;
|
||||
|
||||
Status = gBS->OpenProtocol (
|
||||
ControllerHandle,
|
||||
|
@ -279,8 +280,45 @@ XenPvBlkDxeDriverBindingStart (
|
|||
goto CloseProtocol;
|
||||
}
|
||||
|
||||
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;
|
||||
Media->LastBlock = DivU64x32 (Dev->MediaInfo.Sectors,
|
||||
Media->BlockSize / Dev->MediaInfo.SectorSize) - 1;
|
||||
} else {
|
||||
Media->BlockSize = Dev->MediaInfo.SectorSize;
|
||||
Media->LastBlock = Dev->MediaInfo.Sectors - 1;
|
||||
}
|
||||
ASSERT (Media->BlockSize % 512 == 0);
|
||||
Dev->BlockIo.Media = Media;
|
||||
|
||||
Status = gBS->InstallMultipleProtocolInterfaces (
|
||||
&ControllerHandle,
|
||||
&gEfiBlockIoProtocolGuid, &Dev->BlockIo,
|
||||
NULL
|
||||
);
|
||||
if (EFI_ERROR (Status)) {
|
||||
DEBUG ((EFI_D_ERROR, "XenPvBlk: install protocol fail: %r\n", Status));
|
||||
goto UninitBlockFront;
|
||||
}
|
||||
|
||||
return EFI_SUCCESS;
|
||||
|
||||
UninitBlockFront:
|
||||
FreePool (Media);
|
||||
XenPvBlockFrontShutdown (Dev);
|
||||
CloseProtocol:
|
||||
gBS->CloseProtocol (ControllerHandle, &gXenBusProtocolGuid,
|
||||
This->DriverBindingHandle, ControllerHandle);
|
||||
|
@ -322,6 +360,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);
|
||||
|
||||
|
|
|
@ -77,6 +77,7 @@ extern EFI_COMPONENT_NAME_PROTOCOL gXenPvBlkDxeComponentName;
|
|||
//
|
||||
#include "DriverBinding.h"
|
||||
#include "ComponentName.h"
|
||||
#include "BlockIo.h"
|
||||
|
||||
|
||||
#endif
|
||||
|
|
|
@ -35,6 +35,8 @@
|
|||
ComponentName.h
|
||||
BlockFront.c
|
||||
BlockFront.h
|
||||
BlockIo.c
|
||||
BlockIo.h
|
||||
|
||||
|
||||
[LibraryClasses]
|
||||
|
|
Loading…
Reference in New Issue