When device is behind the IOMMU, VirtioNetDxe is required to use the
device address in bus master operations. RxBuf is allocated using
AllocatePool() which returns the system physical address.

The patch uses VIRTIO_DEVICE_PROTOCOL.AllocateSharedPage() to allocate
the RxBuf and map with BusMasterCommonBuffer so that we can obtain the
device address for RxBuf.

Cc: Ard Biesheuvel <ard.biesheu...@linaro.org>
Cc: Jordan Justen <jordan.l.jus...@intel.com>
Cc: Tom Lendacky <thomas.lenda...@amd.com>
Cc: Laszlo Ersek <ler...@redhat.com>
Contributed-under: TianoCore Contribution Agreement 1.1
Signed-off-by: Brijesh Singh <brijesh.si...@amd.com>
---
 OvmfPkg/VirtioNetDxe/VirtioNet.h        |  3 +
 OvmfPkg/VirtioNetDxe/Events.c           |  6 ++
 OvmfPkg/VirtioNetDxe/SnpInitialize.c    | 75 ++++++++++++++++----
 OvmfPkg/VirtioNetDxe/SnpSharedHelpers.c |  7 +-
 4 files changed, 77 insertions(+), 14 deletions(-)

diff --git a/OvmfPkg/VirtioNetDxe/VirtioNet.h b/OvmfPkg/VirtioNetDxe/VirtioNet.h
index d80d441b50a4..7df51bd044f5 100644
--- a/OvmfPkg/VirtioNetDxe/VirtioNet.h
+++ b/OvmfPkg/VirtioNetDxe/VirtioNet.h
@@ -4,6 +4,7 @@
   Protocol instances for virtio-net devices.
 
   Copyright (C) 2013, Red Hat, Inc.
+  Copyright (c) 2017, AMD Inc, All rights reserved.<BR>
 
   This program and the accompanying materials are licensed and made available
   under the terms and conditions of the BSD License which accompanies this
@@ -85,6 +86,8 @@ typedef struct {
   VOID                        *RxRingMap;        // VirtioRingMap
   UINT8                       *RxBuf;            // VirtioNetInitRx
   UINT16                      RxLastUsed;        // VirtioNetInitRx
+  UINTN                       RxBufNoPages;      // VirtioNetInitRx
+  VOID                        *RxBufMap;         // VirtioMapSharedBuffer
 
   VRING                       TxRing;            // VirtioNetInitRing
   VOID                        *TxRingMap;        // VirtioRingMap
diff --git a/OvmfPkg/VirtioNetDxe/Events.c b/OvmfPkg/VirtioNetDxe/Events.c
index 6950c4d56df1..0586a82cdf09 100644
--- a/OvmfPkg/VirtioNetDxe/Events.c
+++ b/OvmfPkg/VirtioNetDxe/Events.c
@@ -95,4 +95,10 @@ VirtioNetExitBoot (
   //
   Dev->VirtIo->UnmapSharedBuffer (Dev->VirtIo, Dev->TxRingMap);
   Dev->VirtIo->UnmapSharedBuffer (Dev->VirtIo, Dev->RxRingMap);
+
+  //
+  // Unmap Rx buffer so that hypervisor will not be able get readable data 
after
+  // device is reset.
+  //
+  Dev->VirtIo->UnmapSharedBuffer (Dev->VirtIo, Dev->RxBufMap);
 }
diff --git a/OvmfPkg/VirtioNetDxe/SnpInitialize.c 
b/OvmfPkg/VirtioNetDxe/SnpInitialize.c
index 803a38bd4239..6052d40fc6cb 100644
--- a/OvmfPkg/VirtioNetDxe/SnpInitialize.c
+++ b/OvmfPkg/VirtioNetDxe/SnpInitialize.c
@@ -236,7 +236,7 @@ VirtioNetInitTx (
   @param[in,out] Dev       The VNET_DEV driver instance about to enter the
                            EfiSimpleNetworkInitialized state.
 
-  @retval EFI_OUT_OF_RESOURCES  Failed to allocate RX destination area.
+  @retval EFI_OUT_OF_RESOURCES  Failed to allocate or map RX destination area.
   @return                       Status codes from VIRTIO_CFG_WRITE().
   @retval EFI_SUCCESS           RX setup successful. The device is live and may
                                 already be writing to the receive area.
@@ -249,13 +249,17 @@ VirtioNetInitRx (
   IN OUT VNET_DEV *Dev
   )
 {
-  EFI_STATUS Status;
-  UINTN      VirtioNetReqSize;
-  UINTN      RxBufSize;
-  UINT16     RxAlwaysPending;
-  UINTN      PktIdx;
-  UINT16     DescIdx;
-  UINT8      *RxPtr;
+  EFI_STATUS            Status;
+  UINTN                 VirtioNetReqSize;
+  UINTN                 RxBufSize;
+  UINT16                RxAlwaysPending;
+  UINTN                 PktIdx;
+  UINT16                DescIdx;
+  UINT8                 *RxPtr;
+  UINTN                 NumBytes;
+  EFI_PHYSICAL_ADDRESS  RxBufDeviceAddress;
+  UINT64                BufBaseShift;
+  VOID                  *RxBuffer;
 
   //
   // In VirtIo 1.0, the NumBuffers field is mandatory. In 0.9.5, it depends on
@@ -280,11 +284,40 @@ VirtioNetInitRx (
   //
   RxAlwaysPending = (UINT16) MIN (Dev->RxRing.QueueSize / 2, VNET_MAX_PENDING);
 
-  Dev->RxBuf = AllocatePool (RxAlwaysPending * RxBufSize);
-  if (Dev->RxBuf == NULL) {
+  //
+  // The RxBuf is shared between guest and hypervisor, use
+  // AllocateSharedPages() to allocate this memory region and map it with
+  // BusMasterCommonBuffer so that it can be accessed by both guest and
+  // hypervisor.
+  //
+  NumBytes = RxAlwaysPending * RxBufSize;
+  Dev->RxBufNoPages = EFI_SIZE_TO_PAGES (NumBytes);
+  Status = Dev->VirtIo->AllocateSharedPages (
+                          Dev->VirtIo,
+                          Dev->RxBufNoPages,
+                          &RxBuffer
+                          );
+  if (EFI_ERROR (Status)) {
     return EFI_OUT_OF_RESOURCES;
   }
 
+  Status = VirtioMapAllBytesInSharedBuffer (
+             Dev->VirtIo,
+             VirtioOperationBusMasterCommonBuffer,
+             RxBuffer,
+             NumBytes,
+             &RxBufDeviceAddress,
+             &Dev->RxBufMap
+             );
+  if (EFI_ERROR (Status)) {
+    Status = EFI_OUT_OF_RESOURCES;
+    goto FreeSharedBuffer;
+  }
+
+  Dev->RxBuf = RxBuffer;
+
+  BufBaseShift = (UINT64) (UINTN)Dev->RxBuf - (UINT64) RxBufDeviceAddress;
+
   //
   // virtio-0.9.5, 2.4.2 Receiving Used Buffers From the Device
   //
@@ -306,6 +339,11 @@ VirtioNetInitRx (
   DescIdx = 0;
   RxPtr = Dev->RxBuf;
   for (PktIdx = 0; PktIdx < RxAlwaysPending; ++PktIdx) {
+    UINT64    Address;
+
+    Address = (UINTN) RxPtr;
+    Address += BufBaseShift;
+
     //
     // virtio-0.9.5, 2.4.1.2 Updating the Available Ring
     // invisible to the host until we update the Index Field
@@ -315,13 +353,13 @@ VirtioNetInitRx (
     //
     // virtio-0.9.5, 2.4.1.1 Placing Buffers into the Descriptor Table
     //
-    Dev->RxRing.Desc[DescIdx].Addr  = (UINTN) RxPtr;
+    Dev->RxRing.Desc[DescIdx].Addr  = Address;
     Dev->RxRing.Desc[DescIdx].Len   = (UINT32) VirtioNetReqSize;
     Dev->RxRing.Desc[DescIdx].Flags = VRING_DESC_F_WRITE | VRING_DESC_F_NEXT;
     Dev->RxRing.Desc[DescIdx].Next  = (UINT16) (DescIdx + 1);
     RxPtr += Dev->RxRing.Desc[DescIdx++].Len;
 
-    Dev->RxRing.Desc[DescIdx].Addr  = (UINTN) RxPtr;
+    Dev->RxRing.Desc[DescIdx].Addr  = Address;
     Dev->RxRing.Desc[DescIdx].Len   = (UINT32) (RxBufSize - VirtioNetReqSize);
     Dev->RxRing.Desc[DescIdx].Flags = VRING_DESC_F_WRITE;
     RxPtr += Dev->RxRing.Desc[DescIdx++].Len;
@@ -345,10 +383,21 @@ VirtioNetInitRx (
   Status = Dev->VirtIo->SetQueueNotify (Dev->VirtIo, VIRTIO_NET_Q_RX);
   if (EFI_ERROR (Status)) {
     Dev->VirtIo->SetDeviceStatus (Dev->VirtIo, 0);
-    FreePool (Dev->RxBuf);
+    goto UnmapSharedBuffer;
   }
 
   return Status;
+
+UnmapSharedBuffer:
+  Dev->VirtIo->UnmapSharedBuffer (Dev->VirtIo, Dev->RxBufMap);
+
+FreeSharedBuffer:
+  Dev->VirtIo->FreeSharedPages (
+                 Dev->VirtIo,
+                 Dev->RxBufNoPages,
+                 (VOID *) Dev->RxBuf
+                 );
+  return Status;
 }
 
 
diff --git a/OvmfPkg/VirtioNetDxe/SnpSharedHelpers.c 
b/OvmfPkg/VirtioNetDxe/SnpSharedHelpers.c
index 9fedb72fdbd4..4c9d9ece0790 100644
--- a/OvmfPkg/VirtioNetDxe/SnpSharedHelpers.c
+++ b/OvmfPkg/VirtioNetDxe/SnpSharedHelpers.c
@@ -39,7 +39,12 @@ VirtioNetShutdownRx (
   IN OUT VNET_DEV *Dev
   )
 {
-  FreePool (Dev->RxBuf);
+  Dev->VirtIo->UnmapSharedBuffer (Dev->VirtIo, Dev->RxBufMap);
+  Dev->VirtIo->FreeSharedPages (
+                 Dev->VirtIo,
+                 Dev->RxBufNoPages,
+                 (VOID *) Dev->RxBuf
+                 );
 }
 
 
-- 
2.7.4

_______________________________________________
edk2-devel mailing list
edk2-devel@lists.01.org
https://lists.01.org/mailman/listinfo/edk2-devel

Reply via email to