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

Reply via email to