--- /dev/null
+/** @file\r
+ BlockIo implementation for Xen PV Block driver.\r
+\r
+ This file is implementing the interface between the actual driver in\r
+ BlockFront.c to the BlockIo protocol.\r
+\r
+ Copyright (C) 2014, Citrix Ltd.\r
+\r
+ This program and the accompanying materials\r
+ are licensed and made available under the terms and conditions of the BSD License\r
+ which accompanies this distribution. The full text of the license may be found at\r
+ http://opensource.org/licenses/bsd-license.php\r
+\r
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#include "XenPvBlkDxe.h"\r
+\r
+#include "BlockFront.h"\r
+\r
+///\r
+/// Block I/O Media structure\r
+///\r
+GLOBAL_REMOVE_IF_UNREFERENCED\r
+EFI_BLOCK_IO_MEDIA gXenPvBlkDxeBlockIoMedia = {\r
+ 0, // MediaId\r
+ FALSE, // RemovableMedia\r
+ FALSE, // MediaPresent\r
+ FALSE, // LogicalPartition\r
+ TRUE, // ReadOnly\r
+ FALSE, // WriteCaching\r
+ 512, // BlockSize\r
+ 512, // IoAlign, BlockFront does not support less than 512 bits-aligned.\r
+ 0, // LastBlock\r
+ 0, // LowestAlignedLba\r
+ 0, // LogicalBlocksPerPhysicalBlock\r
+ 0 // OptimalTransferLengthGranularity\r
+};\r
+\r
+///\r
+/// Block I/O Protocol instance\r
+///\r
+GLOBAL_REMOVE_IF_UNREFERENCED\r
+EFI_BLOCK_IO_PROTOCOL gXenPvBlkDxeBlockIo = {\r
+ EFI_BLOCK_IO_PROTOCOL_REVISION3, // Revision\r
+ &gXenPvBlkDxeBlockIoMedia, // Media\r
+ XenPvBlkDxeBlockIoReset, // Reset\r
+ XenPvBlkDxeBlockIoReadBlocks, // ReadBlocks\r
+ XenPvBlkDxeBlockIoWriteBlocks, // WriteBlocks\r
+ XenPvBlkDxeBlockIoFlushBlocks // FlushBlocks\r
+};\r
+\r
+\r
+\r
+\r
+/**\r
+ Read/Write BufferSize bytes from Lba into Buffer.\r
+\r
+ This function is commun to XenPvBlkDxeBlockIoReadBlocks and\r
+ XenPvBlkDxeBlockIoWriteBlocks.\r
+\r
+ @param This Indicates a pointer to the calling context.\r
+ @param MediaId Id of the media, changes every time the media is replaced.\r
+ @param Lba The starting Logical Block Address to read from/write to.\r
+ @param BufferSize Size of Buffer, must be a multiple of device block size.\r
+ @param Buffer A pointer to the destination/source buffer for the data.\r
+ @param IsWrite Indicate if the operation is write or read.\r
+\r
+ @return See description of XenPvBlkDxeBlockIoReadBlocks and\r
+ XenPvBlkDxeBlockIoWriteBlocks.\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+XenPvBlkDxeBlockIoReadWriteBlocks (\r
+ IN EFI_BLOCK_IO_PROTOCOL *This,\r
+ IN UINT32 MediaId,\r
+ IN EFI_LBA Lba,\r
+ IN UINTN BufferSize,\r
+ IN OUT VOID *Buffer,\r
+ IN BOOLEAN IsWrite\r
+ )\r
+{\r
+ XEN_BLOCK_FRONT_IO IoData;\r
+ EFI_BLOCK_IO_MEDIA *Media = This->Media;\r
+ UINTN Sector;\r
+ EFI_STATUS Status;\r
+\r
+ if (Buffer == NULL) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+ if (BufferSize == 0) {\r
+ return EFI_SUCCESS;\r
+ }\r
+\r
+ if (BufferSize % Media->BlockSize != 0) {\r
+ DEBUG ((EFI_D_ERROR, "XenPvBlkDxe: Bad buffer size: 0x%X\n", BufferSize));\r
+ return EFI_BAD_BUFFER_SIZE;\r
+ }\r
+\r
+ if (Lba > Media->LastBlock ||\r
+ (BufferSize / Media->BlockSize) - 1 > Media->LastBlock - Lba) {\r
+ DEBUG ((EFI_D_ERROR, "XenPvBlkDxe: %a with invalid LBA: 0x%LX, size: 0x%x\n",\r
+ IsWrite ? "Write" : "Read", Lba, BufferSize));\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ if (IsWrite && Media->ReadOnly) {\r
+ return EFI_WRITE_PROTECTED;\r
+ }\r
+\r
+ if ((Media->IoAlign > 1) && (UINTN)Buffer & (Media->IoAlign - 1)) {\r
+ //\r
+ // Grub2 does not appear to respect IoAlign of 512, so reallocate the\r
+ // buffer here.\r
+ //\r
+ VOID *NewBuffer;\r
+\r
+ //\r
+ // Try again with a properly aligned buffer.\r
+ //\r
+ NewBuffer = AllocateAlignedPages((BufferSize + EFI_PAGE_SIZE) / EFI_PAGE_SIZE,\r
+ Media->IoAlign);\r
+ if (!IsWrite) {\r
+ Status = XenPvBlkDxeBlockIoReadBlocks (This, MediaId,\r
+ Lba, BufferSize, NewBuffer);\r
+ CopyMem (Buffer, NewBuffer, BufferSize);\r
+ } else {\r
+ CopyMem (NewBuffer, Buffer, BufferSize);\r
+ Status = XenPvBlkDxeBlockIoWriteBlocks (This, MediaId,\r
+ Lba, BufferSize, NewBuffer);\r
+ }\r
+ FreeAlignedPages (NewBuffer, (BufferSize + EFI_PAGE_SIZE) / EFI_PAGE_SIZE);\r
+ return Status;\r
+ }\r
+\r
+ IoData.Dev = XEN_BLOCK_FRONT_FROM_BLOCK_IO (This);\r
+ Sector = Lba * (Media->BlockSize / 512);\r
+\r
+ while (BufferSize > 0) {\r
+ if (((UINTN)Buffer & EFI_PAGE_MASK) == 0) {\r
+ IoData.Size = MIN (BLKIF_MAX_SEGMENTS_PER_REQUEST * EFI_PAGE_SIZE,\r
+ BufferSize);\r
+ } else {\r
+ IoData.Size = MIN ((BLKIF_MAX_SEGMENTS_PER_REQUEST - 1) * EFI_PAGE_SIZE,\r
+ BufferSize);\r
+ }\r
+\r
+ IoData.Buffer = Buffer;\r
+ IoData.Sector = Sector;\r
+ BufferSize -= IoData.Size;\r
+ Buffer = (VOID*) ((UINTN) Buffer + IoData.Size);\r
+ Sector += IoData.Size / 512;\r
+ Status = XenPvBlockIo (&IoData, IsWrite);\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG ((EFI_D_ERROR, "XenPvBlkDxe: Error durring %a operation.\n",\r
+ IsWrite ? "write" : "read"));\r
+ return Status;\r
+ }\r
+ }\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+ Read BufferSize bytes from Lba into Buffer.\r
+\r
+ @param This Indicates a pointer to the calling context.\r
+ @param MediaId Id of the media, changes every time the media is replaced.\r
+ @param Lba The starting Logical Block Address to read from\r
+ @param BufferSize Size of Buffer, must be a multiple of device block size.\r
+ @param Buffer A pointer to the destination buffer for the data. The caller is\r
+ responsible for either having implicit or explicit ownership of the buffer.\r
+\r
+ @retval EFI_SUCCESS The data was read correctly from the device.\r
+ @retval EFI_DEVICE_ERROR The device reported an error while performing the read.\r
+ @retval EFI_NO_MEDIA There is no media in the device.\r
+ @retval EFI_MEDIA_CHANGED The MediaId does not matched the current device.\r
+ @retval EFI_BAD_BUFFER_SIZE The Buffer was not a multiple of the block size of the device.\r
+ @retval EFI_INVALID_PARAMETER The read request contains LBAs that are not valid,\r
+ or the buffer is not on proper alignment.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+XenPvBlkDxeBlockIoReadBlocks (\r
+ IN EFI_BLOCK_IO_PROTOCOL *This,\r
+ IN UINT32 MediaId,\r
+ IN EFI_LBA Lba,\r
+ IN UINTN BufferSize,\r
+ OUT VOID *Buffer\r
+ )\r
+{\r
+ return XenPvBlkDxeBlockIoReadWriteBlocks (This,\r
+ MediaId, Lba, BufferSize, Buffer, FALSE);\r
+}\r
+\r
+/**\r
+ Write BufferSize bytes from Lba into Buffer.\r
+\r
+ @param This Indicates a pointer to the calling context.\r
+ @param MediaId The media ID that the write request is for.\r
+ @param Lba The starting logical block address to be written. The caller is\r
+ responsible for writing to only legitimate locations.\r
+ @param BufferSize Size of Buffer, must be a multiple of device block size.\r
+ @param Buffer A pointer to the source buffer for the data.\r
+\r
+ @retval EFI_SUCCESS The data was written correctly to the device.\r
+ @retval EFI_WRITE_PROTECTED The device can not be written to.\r
+ @retval EFI_DEVICE_ERROR The device reported an error while performing the write.\r
+ @retval EFI_NO_MEDIA There is no media in the device.\r
+ @retval EFI_MEDIA_CHNAGED The MediaId does not matched the current device.\r
+ @retval EFI_BAD_BUFFER_SIZE The Buffer was not a multiple of the block size of the device.\r
+ @retval EFI_INVALID_PARAMETER The write request contains LBAs that are not valid,\r
+ or the buffer is not on proper alignment.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+XenPvBlkDxeBlockIoWriteBlocks (\r
+ IN EFI_BLOCK_IO_PROTOCOL *This,\r
+ IN UINT32 MediaId,\r
+ IN EFI_LBA Lba,\r
+ IN UINTN BufferSize,\r
+ IN VOID *Buffer\r
+ )\r
+{\r
+ return XenPvBlkDxeBlockIoReadWriteBlocks (This,\r
+ MediaId, Lba, BufferSize, Buffer, TRUE);\r
+}\r
+\r
+/**\r
+ Flush the Block Device.\r
+\r
+ @param This Indicates a pointer to the calling context.\r
+\r
+ @retval EFI_SUCCESS All outstanding data was written to the device\r
+ @retval EFI_DEVICE_ERROR The device reported an error while writting back the data\r
+ @retval EFI_NO_MEDIA There is no media in the device.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+XenPvBlkDxeBlockIoFlushBlocks (\r
+ IN EFI_BLOCK_IO_PROTOCOL *This\r
+ )\r
+{\r
+ XenPvBlockSync (XEN_BLOCK_FRONT_FROM_BLOCK_IO (This));\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Reset the block device hardware.\r
+\r
+ @param[in] This Indicates a pointer to the calling context.\r
+ @param[in] ExtendedVerification Not used.\r
+\r
+ @retval EFI_SUCCESS The device was reset.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+XenPvBlkDxeBlockIoReset (\r
+ IN EFI_BLOCK_IO_PROTOCOL *This,\r
+ IN BOOLEAN ExtendedVerification\r
+ )\r
+{\r
+ //\r
+ // Since the initialization of the devices is done, then the device is\r
+ // working correctly.\r
+ //\r
+ return EFI_SUCCESS;\r
+}\r
--- /dev/null
+/** @file\r
+ BlockIo function declaration for Xen PV block driver.\r
+\r
+ Copyright (C) 2014, Citrix Ltd.\r
+\r
+ This program and the accompanying materials\r
+ are licensed and made available under the terms and conditions of the BSD License\r
+ which accompanies this distribution. The full text of the license may be found at\r
+ http://opensource.org/licenses/bsd-license.php\r
+\r
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+/**\r
+ Read BufferSize bytes from Lba into Buffer.\r
+\r
+ @param This Indicates a pointer to the calling context.\r
+ @param MediaId Id of the media, changes every time the media is replaced.\r
+ @param Lba The starting Logical Block Address to read from\r
+ @param BufferSize Size of Buffer, must be a multiple of device block size.\r
+ @param Buffer A pointer to the destination buffer for the data. The caller is\r
+ responsible for either having implicit or explicit ownership of the buffer.\r
+\r
+ @retval EFI_SUCCESS The data was read correctly from the device.\r
+ @retval EFI_DEVICE_ERROR The device reported an error while performing the read.\r
+ @retval EFI_NO_MEDIA There is no media in the device.\r
+ @retval EFI_MEDIA_CHANGED The MediaId does not matched the current device.\r
+ @retval EFI_BAD_BUFFER_SIZE The Buffer was not a multiple of the block size of the device.\r
+ @retval EFI_INVALID_PARAMETER The read request contains LBAs that are not valid,\r
+ or the buffer is not on proper alignment.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+XenPvBlkDxeBlockIoReadBlocks (\r
+ IN EFI_BLOCK_IO_PROTOCOL *This,\r
+ IN UINT32 MediaId,\r
+ IN EFI_LBA Lba,\r
+ IN UINTN BufferSize,\r
+ OUT VOID *Buffer\r
+ );\r
+\r
+/**\r
+ Write BufferSize bytes from Lba into Buffer.\r
+\r
+ @param This Indicates a pointer to the calling context.\r
+ @param MediaId The media ID that the write request is for.\r
+ @param Lba The starting logical block address to be written. The caller is\r
+ responsible for writing to only legitimate locations.\r
+ @param BufferSize Size of Buffer, must be a multiple of device block size.\r
+ @param Buffer A pointer to the source buffer for the data.\r
+\r
+ @retval EFI_SUCCESS The data was written correctly to the device.\r
+ @retval EFI_WRITE_PROTECTED The device can not be written to.\r
+ @retval EFI_DEVICE_ERROR The device reported an error while performing the write.\r
+ @retval EFI_NO_MEDIA There is no media in the device.\r
+ @retval EFI_MEDIA_CHNAGED The MediaId does not matched the current device.\r
+ @retval EFI_BAD_BUFFER_SIZE The Buffer was not a multiple of the block size of the device.\r
+ @retval EFI_INVALID_PARAMETER The write request contains LBAs that are not valid,\r
+ or the buffer is not on proper alignment.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+XenPvBlkDxeBlockIoWriteBlocks (\r
+ IN EFI_BLOCK_IO_PROTOCOL *This,\r
+ IN UINT32 MediaId,\r
+ IN EFI_LBA Lba,\r
+ IN UINTN BufferSize,\r
+ IN VOID *Buffer\r
+ );\r
+\r
+/**\r
+ Flush the Block Device.\r
+\r
+ @param This Indicates a pointer to the calling context.\r
+\r
+ @retval EFI_SUCCESS All outstanding data was written to the device\r
+ @retval EFI_DEVICE_ERROR The device reported an error while writting back the data\r
+ @retval EFI_NO_MEDIA There is no media in the device.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+XenPvBlkDxeBlockIoFlushBlocks (\r
+ IN EFI_BLOCK_IO_PROTOCOL *This\r
+ );\r
+\r
+/**\r
+ Reset the block device hardware.\r
+\r
+ @param[in] This Indicates a pointer to the calling context.\r
+ @param[in] ExtendedVerification Not used.\r
+\r
+ @retval EFI_SUCCESS The device was reset.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+XenPvBlkDxeBlockIoReset (\r
+ IN EFI_BLOCK_IO_PROTOCOL *This,\r
+ IN BOOLEAN ExtendedVerification\r
+ );\r
+\r
+extern EFI_BLOCK_IO_MEDIA gXenPvBlkDxeBlockIoMedia;\r
+extern EFI_BLOCK_IO_PROTOCOL gXenPvBlkDxeBlockIo;\r
EFI_STATUS Status;\r
XENBUS_PROTOCOL *XenBusIo;\r
XEN_BLOCK_FRONT_DEVICE *Dev;\r
+ EFI_BLOCK_IO_MEDIA *Media;\r
\r
Status = gBS->OpenProtocol (\r
ControllerHandle,\r
goto CloseProtocol;\r
}\r
\r
+ CopyMem (&Dev->BlockIo, &gXenPvBlkDxeBlockIo, sizeof (EFI_BLOCK_IO_PROTOCOL));\r
+ Media = AllocateCopyPool (sizeof (EFI_BLOCK_IO_MEDIA),\r
+ &gXenPvBlkDxeBlockIoMedia);\r
+ if (Dev->MediaInfo.VDiskInfo & VDISK_REMOVABLE) {\r
+ Media->RemovableMedia = TRUE;\r
+ }\r
+ Media->MediaPresent = TRUE;\r
+ Media->ReadOnly = !Dev->MediaInfo.ReadWrite;\r
+ if (Dev->MediaInfo.CdRom) {\r
+ //\r
+ // If it's a cdrom, the blocksize value need to be 2048 for OVMF to\r
+ // recognize it as a cdrom:\r
+ // MdeModulePkg/Universal/Disk/PartitionDxe/ElTorito.c\r
+ //\r
+ Media->BlockSize = 2048;\r
+ Media->LastBlock = DivU64x32 (Dev->MediaInfo.Sectors,\r
+ Media->BlockSize / Dev->MediaInfo.SectorSize) - 1;\r
+ } else {\r
+ Media->BlockSize = Dev->MediaInfo.SectorSize;\r
+ Media->LastBlock = Dev->MediaInfo.Sectors - 1;\r
+ }\r
+ ASSERT (Media->BlockSize % 512 == 0);\r
+ Dev->BlockIo.Media = Media;\r
+\r
+ Status = gBS->InstallMultipleProtocolInterfaces (\r
+ &ControllerHandle,\r
+ &gEfiBlockIoProtocolGuid, &Dev->BlockIo,\r
+ NULL\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG ((EFI_D_ERROR, "XenPvBlk: install protocol fail: %r\n", Status));\r
+ goto UninitBlockFront;\r
+ }\r
+\r
return EFI_SUCCESS;\r
\r
+UninitBlockFront:\r
+ FreePool (Media);\r
+ XenPvBlockFrontShutdown (Dev);\r
CloseProtocol:\r
gBS->CloseProtocol (ControllerHandle, &gXenBusProtocolGuid,\r
This->DriverBindingHandle, ControllerHandle);\r
IN EFI_HANDLE *ChildHandleBuffer OPTIONAL\r
)\r
{\r
+ EFI_BLOCK_IO_PROTOCOL *BlockIo;\r
+ XEN_BLOCK_FRONT_DEVICE *Dev;\r
+ EFI_BLOCK_IO_MEDIA *Media;\r
+ EFI_STATUS Status;\r
+\r
+ Status = gBS->OpenProtocol (\r
+ ControllerHandle, &gEfiBlockIoProtocolGuid,\r
+ (VOID **)&BlockIo,\r
+ This->DriverBindingHandle, ControllerHandle,\r
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ Status = gBS->UninstallProtocolInterface (ControllerHandle,\r
+ &gEfiBlockIoProtocolGuid, BlockIo);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ Media = BlockIo->Media;\r
+ Dev = XEN_BLOCK_FRONT_FROM_BLOCK_IO (BlockIo);\r
+ XenPvBlockFrontShutdown (Dev);\r
+\r
+ FreePool (Media);\r
+\r
gBS->CloseProtocol (ControllerHandle, &gXenBusProtocolGuid,\r
This->DriverBindingHandle, ControllerHandle);\r
\r