RxBuf is shared between guest and hypervisor, use VIRTIO_DEVICE_PROTOCOL.AllocateSharedPages() to allocate this memory region and map it with BusMasterCommonBuffer operation so that it can be accessed by both guest and hypervisor.
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 | 76 ++++++++++++++++---- OvmfPkg/VirtioNetDxe/SnpSharedHelpers.c | 7 +- 4 files changed, 78 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..bdc3fd7ac6a2 100644 --- a/OvmfPkg/VirtioNetDxe/SnpInitialize.c +++ b/OvmfPkg/VirtioNetDxe/SnpInitialize.c @@ -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,41 @@ VirtioNetInitRx ( // RxAlwaysPending = (UINT16) MIN (Dev->RxRing.QueueSize / 2, VNET_MAX_PENDING); - Dev->RxBuf = AllocatePool (RxAlwaysPending * RxBufSize); - if (Dev->RxBuf == NULL) { - return EFI_OUT_OF_RESOURCES; + // + // The RxBuf is shared between guest and hypervisor, use SharedPages() to + // allocate this memory region and map it with BusMasterCommonBuffer + // operation so that it can be accessed equally 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)) { + Status = EFI_OUT_OF_RESOURCES; + return Status; } + 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 +340,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 +354,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 +384,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