When VIRTIO_F_IOMMU_PLATFORM feature bit in set then try locating IOMMU protocol. If IOMMU protocol is available, then use the IOMMU protocols functions to allocate, free, map and unmap the host buffer to device buffer.
Cc: Jordan Justen <[email protected]> Cc: Laszlo Ersek <[email protected]> Cc: Jason Wang <[email protected]> Cc: Michael S. Tsirkin <[email protected]> Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Brijesh Singh <[email protected]> --- OvmfPkg/VirtioBlkDxe/VirtioBlk.inf | 4 + OvmfPkg/VirtioBlkDxe/VirtioBlk.c | 125 ++++++++++++++++++-- 2 files changed, 118 insertions(+), 11 deletions(-) diff --git a/OvmfPkg/VirtioBlkDxe/VirtioBlk.inf b/OvmfPkg/VirtioBlkDxe/VirtioBlk.inf index 53d5a164a0b8..12577c5f700f 100644 --- a/OvmfPkg/VirtioBlkDxe/VirtioBlk.inf +++ b/OvmfPkg/VirtioBlkDxe/VirtioBlk.inf @@ -41,3 +41,7 @@ [LibraryClasses] [Protocols] gEfiBlockIoProtocolGuid ## BY_START gVirtioDeviceProtocolGuid ## TO_START + gEdkiiIoMmuProtocolGuid ## SOMETIMES_CONSUMES + +[Depex] + gEdkiiIoMmuProtocolGuid OR gIoMmuAbsentProtocolGuid diff --git a/OvmfPkg/VirtioBlkDxe/VirtioBlk.c b/OvmfPkg/VirtioBlkDxe/VirtioBlk.c index 3ce72281c204..f78052c4ecc0 100644 --- a/OvmfPkg/VirtioBlkDxe/VirtioBlk.c +++ b/OvmfPkg/VirtioBlkDxe/VirtioBlk.c @@ -23,6 +23,8 @@ **/ +#include <Protocol/IoMmu.h> + #include <IndustryStandard/VirtioBlk.h> #include <Library/BaseMemoryLib.h> #include <Library/DebugLib.h> @@ -33,6 +35,8 @@ #include "VirtioBlk.h" +STATIC EDKII_IOMMU_PROTOCOL *mIoMmuProtocol; + /** Convenience macros to read and write region 0 IO space elements of the @@ -247,13 +251,49 @@ SynchronousRequest ( ) { UINT32 BlockSize; - volatile VIRTIO_BLK_REQ Request; - volatile UINT8 HostStatus; + volatile VIRTIO_BLK_REQ LocalRequest; + volatile UINT8 LocalHostStatus; + volatile VIRTIO_BLK_REQ *Request; + volatile UINT8 *HostStatus; DESC_INDICES Indices; + VOID *IommuBuffer; + UINT32 NumPages; + VOID *Mapping; + EFI_STATUS Status; + EFI_PHYSICAL_ADDRESS DeviceBuffer; BlockSize = Dev->BlockIoMedia.BlockSize; // + // set NumPages to suppress incorrect compiler/analyzer warnings + // + NumPages = 0; + + // + // If IOMMU platform is enabled for this device then allocate Request and + // HostStatus variable dynamically using IOMMU allocator + // + if (mIoMmuProtocol) { + EFI_STATUS Status; + + NumPages = (UINT32)EFI_SIZE_TO_PAGES (sizeof (*Request) + sizeof (*HostStatus)); + Status = mIoMmuProtocol->AllocateBuffer (mIoMmuProtocol, 0, + EfiBootServicesData, NumPages, &IommuBuffer, + EDKII_IOMMU_ATTRIBUTE_MEMORY_CACHED); + if (EFI_ERROR (Status)) { + return Status; + } + + Request = IommuBuffer; + HostStatus = IommuBuffer + sizeof(*Request); + } else { + Request = &LocalRequest; + HostStatus = &LocalHostStatus; + IommuBuffer = NULL; + Mapping = NULL; + } + + // // ensured by VirtioBlkInit() // ASSERT (BlockSize > 0); @@ -268,18 +308,18 @@ SynchronousRequest ( // Prepare virtio-blk request header, setting zero size for flush. // IO Priority is homogeneously 0. // - Request.Type = RequestIsWrite ? + Request->Type = RequestIsWrite ? (BufferSize == 0 ? VIRTIO_BLK_T_FLUSH : VIRTIO_BLK_T_OUT) : VIRTIO_BLK_T_IN; - Request.IoPrio = 0; - Request.Sector = MultU64x32(Lba, BlockSize / 512); + Request->IoPrio = 0; + Request->Sector = MultU64x32(Lba, BlockSize / 512); VirtioPrepare (&Dev->Ring, &Indices); // // preset a host status for ourselves that we do not accept as success // - HostStatus = VIRTIO_BLK_S_IOERR; + *HostStatus = VIRTIO_BLK_S_IOERR; // // ensured by VirtioBlkInit() -- this predicate, in combination with the @@ -290,7 +330,7 @@ SynchronousRequest ( // // virtio-blk header in first desc // - VirtioAppendDesc (&Dev->Ring, (UINTN) &Request, sizeof Request, + VirtioAppendDesc (&Dev->Ring, (UINTN) Request, sizeof *Request, VRING_DESC_F_NEXT, &Indices); // @@ -308,6 +348,42 @@ SynchronousRequest ( ASSERT (BufferSize <= SIZE_1GB); // + // When IOMMU platform is enabled, map the host buffer to device + // + if (mIoMmuProtocol) { + EDKII_IOMMU_OPERATION Operation; + UINTN NumBytes; + + NumBytes = BufferSize; + + if (RequestIsWrite) { + Operation = EdkiiIoMmuOperationBusMasterRead; + } else { + Operation = EdkiiIoMmuOperationBusMasterWrite; + } + + Status = mIoMmuProtocol->Map (mIoMmuProtocol, Operation, (VOID *)Buffer, + &NumBytes, &DeviceBuffer, &Mapping); + if (EFI_ERROR (Status)) { + Status = EFI_DEVICE_ERROR; + goto HandleExit; + } + + // + // Verify that we are able to map the required size + // + if (NumBytes < BufferSize) { + DEBUG ((DEBUG_ERROR, "%a: request %d got %d\n", __FUNCTION__, + BufferSize, NumBytes)); + + Status = EFI_DEVICE_ERROR; + mIoMmuProtocol->Unmap (mIoMmuProtocol, Mapping); + goto HandleExit; + } + Buffer = (VOID *)DeviceBuffer; + } + + // // VRING_DESC_F_WRITE is interpreted from the host's point of view. // VirtioAppendDesc (&Dev->Ring, (UINTN) Buffer, (UINT32) BufferSize, @@ -318,7 +394,7 @@ SynchronousRequest ( // // host status in last (second or third) desc // - VirtioAppendDesc (&Dev->Ring, (UINTN) &HostStatus, sizeof HostStatus, + VirtioAppendDesc (&Dev->Ring, (UINTN) HostStatus, sizeof *HostStatus, VRING_DESC_F_WRITE, &Indices); // @@ -326,11 +402,23 @@ SynchronousRequest ( // if (VirtioFlush (Dev->VirtIo, 0, &Dev->Ring, &Indices, NULL) == EFI_SUCCESS && - HostStatus == VIRTIO_BLK_S_OK) { - return EFI_SUCCESS; + *HostStatus == VIRTIO_BLK_S_OK) { + Status = EFI_SUCCESS; + goto HandleExit; } - return EFI_DEVICE_ERROR; + Status = EFI_DEVICE_ERROR; + +HandleExit: + if (Mapping) { + mIoMmuProtocol->Unmap (mIoMmuProtocol, Mapping); + } + + if (IommuBuffer) { + mIoMmuProtocol->FreeBuffer (mIoMmuProtocol, NumPages, IommuBuffer); + } + + return Status; } @@ -692,6 +780,21 @@ VirtioBlkInit ( } } + // + // If IOMMU_PLATFORM feature is requested then try to locate IOMMU + // protocol before acking that we support IOMMU_PLATFORM feature + // + if (Features & VIRTIO_F_IOMMU_PLATFORM) { + Status = gBS->LocateProtocol (&gEdkiiIoMmuProtocolGuid, NULL, (VOID **)&mIoMmuProtocol); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "%a: Failed to locate IOMMU protocol\n", __FUNCTION__)); + goto Failed; + } + + Features &= VIRTIO_F_IOMMU_PLATFORM; + VirtioRingUseIommu (&Dev->Ring, mIoMmuProtocol); + } + Features &= VIRTIO_BLK_F_BLK_SIZE | VIRTIO_BLK_F_TOPOLOGY | VIRTIO_BLK_F_RO | VIRTIO_BLK_F_FLUSH | VIRTIO_F_VERSION_1; -- 2.7.4 _______________________________________________ edk2-devel mailing list [email protected] https://lists.01.org/mailman/listinfo/edk2-devel

