@@ -13,15 +13,15 @@
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, WITHOUT
WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
**/
#ifndef _VIRTIO_NET_DXE_H_
#define _VIRTIO_NET_DXE_H_
-#include <IndustryStandard/VirtioNet.h>
+#include <IndustryStandard/Virtio10Net.h>
#include <Library/DebugLib.h>
#include <Library/VirtioLib.h>
#include <Protocol/ComponentName.h>
#include <Protocol/ComponentName2.h>
#include <Protocol/DevicePath.h>
#include <Protocol/DriverBinding.h>
#include <Protocol/SimpleNetwork.h>
@@ -85,15 +85,15 @@ typedef struct {
UINT8 *RxBuf; // VirtioNetInitRx
UINT16 RxLastUsed; // VirtioNetInitRx
VRING TxRing; // VirtioNetInitRing
UINT16 TxMaxPending; // VirtioNetInitTx
UINT16 TxCurPending; // VirtioNetInitTx
UINT16 *TxFreeStack; // VirtioNetInitTx
- VIRTIO_NET_REQ TxSharedReq; // VirtioNetInitTx
+ VIRTIO_1_0_NET_REQ TxSharedReq; // VirtioNetInitTx
UINT16 TxLastUsed; // VirtioNetInitTx
} VNET_DEV;
//
// In order to avoid duplication of interface documentation, please find all
// leading comments near the respective function / variable definitions (not
@@ -134,52 +134,66 @@ ReleaseQueue:
STATIC
EFI_STATUS
EFIAPI
VirtioNetInitTx (
IN OUT VNET_DEV *Dev
)
{
+ UINTN TxSharedReqSize;
UINTN PktIdx;
Dev->TxMaxPending = (UINT16) MIN (Dev->TxRing.QueueSize / 2,
VNET_MAX_PENDING);
Dev->TxCurPending = 0;
Dev->TxFreeStack = AllocatePool (Dev->TxMaxPending *
sizeof *Dev->TxFreeStack);
if (Dev->TxFreeStack == NULL) {
return EFI_OUT_OF_RESOURCES;
}
+ //
+ // In VirtIo 1.0, the NumBuffers field is mandatory. In 0.9.5, it depends on
+ // VIRTIO_NET_F_MRG_RXBUF, which we never negotiate.
+ //
+ TxSharedReqSize = (Dev->VirtIo->Revision < VIRTIO_SPEC_REVISION (1, 0, 0)) ?
+ sizeof Dev->TxSharedReq.Legacy :
+ sizeof Dev->TxSharedReq;
+
for (PktIdx = 0; PktIdx < Dev->TxMaxPending; ++PktIdx) {
UINT16 DescIdx;
DescIdx = (UINT16) (2 * PktIdx);
Dev->TxFreeStack[PktIdx] = DescIdx;
//
// For each possibly pending packet, lay out the descriptor for the common
// (unmodified by the host) virtio-net request header.
//
Dev->TxRing.Desc[DescIdx].Addr = (UINTN) &Dev->TxSharedReq;
- Dev->TxRing.Desc[DescIdx].Len = sizeof Dev->TxSharedReq;
+ Dev->TxRing.Desc[DescIdx].Len = (UINT32) TxSharedReqSize;
Dev->TxRing.Desc[DescIdx].Flags = VRING_DESC_F_NEXT;
Dev->TxRing.Desc[DescIdx].Next = (UINT16) (DescIdx + 1);
//
// The second descriptor of each pending TX packet is updated on the fly,
// but it always terminates the descriptor chain of the packet.
//
Dev->TxRing.Desc[DescIdx + 1].Flags = 0;
}
//
// virtio-0.9.5, Appendix C, Packet Transmission
//
- Dev->TxSharedReq.Flags = 0;
- Dev->TxSharedReq.GsoType = VIRTIO_NET_HDR_GSO_NONE;
+ Dev->TxSharedReq.Legacy.Flags = 0;
+ Dev->TxSharedReq.Legacy.GsoType = VIRTIO_NET_HDR_GSO_NONE;
+
+ //
+ // For VirtIo 1.0 only -- the field exists, but it is unused
+ //
+ Dev->TxSharedReq.NumBuffers = 0;
//
// virtio-0.9.5, 2.4.2 Receiving Used Buffers From the Device
//
MemoryFence ();
Dev->TxLastUsed = *Dev->TxRing.Used.Idx;
ASSERT (Dev->TxLastUsed == 0);
@@ -219,27 +233,36 @@ STATIC
EFI_STATUS
EFIAPI
VirtioNetInitRx (
IN OUT VNET_DEV *Dev
)
{
EFI_STATUS Status;
+ UINTN VirtioNetReqSize;
UINTN RxBufSize;
UINT16 RxAlwaysPending;
UINTN PktIdx;
UINT16 DescIdx;
UINT8 *RxPtr;
//
+ // In VirtIo 1.0, the NumBuffers field is mandatory. In 0.9.5, it depends on
+ // VIRTIO_NET_F_MRG_RXBUF, which we never negotiate.
+ //
+ VirtioNetReqSize = (Dev->VirtIo->Revision < VIRTIO_SPEC_REVISION (1, 0, 0)) ?
+ sizeof (VIRTIO_NET_REQ) :
+ sizeof (VIRTIO_1_0_NET_REQ);
+
+ //
// For each incoming packet we must supply two descriptors:
// - the recipient for the virtio-net request header, plus
// - the recipient for the network data (which consists of Ethernet header
// and Ethernet payload).
//
- RxBufSize = sizeof (VIRTIO_NET_REQ) +
+ RxBufSize = VirtioNetReqSize +
(Dev->Snm.MediaHeaderSize + Dev->Snm.MaxPacketSize);
//
// Limit the number of pending RX packets if the queue is big. The division
// by two is due to the above "two descriptors per packet" trait.
//
RxAlwaysPending = (UINT16) MIN (Dev->RxRing.QueueSize / 2, VNET_MAX_PENDING);
@@ -276,22 +299,21 @@ VirtioNetInitRx (
//
Dev->RxRing.Avail.Ring[PktIdx] = DescIdx;
//
// 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].Len = sizeof (VIRTIO_NET_REQ);
+ 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].Len = (UINT32) (RxBufSize -
- sizeof (VIRTIO_NET_REQ));
+ Dev->RxRing.Desc[DescIdx].Len = (UINT32) (RxBufSize - VirtioNetReqSize);
Dev->RxRing.Desc[DescIdx].Flags = VRING_DESC_F_WRITE;
RxPtr += Dev->RxRing.Desc[DescIdx++].Len;
}
//
// virtio-0.9.5, 2.4.1.3 Updating the Index Field
//
In virtio-0.9.5, the size of the virtio-net packet header depends on whether the VIRTIO_NET_F_MRG_RXBUF feature is negotiated -- the "num_buffers" field is only appended to the header if the feature is negotiated. Since we never negotiate this feature, VirtioNetDxe never allocates room for the "num_buffers" field. With virtio-1.0, the "num_buffers" field is always there (although it doesn't carry useful information without VIRTIO_NET_F_MRG_RXBUF). Adapt the buffers that depend on the virtio-net header size (otherwise we have skewed / truncated packets). Cc: Ard Biesheuvel <ard.biesheuvel@linaro.org> Cc: Jordan Justen <jordan.l.justen@intel.com> Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Laszlo Ersek <lersek@redhat.com> --- OvmfPkg/VirtioNetDxe/VirtioNet.h | 4 +-- OvmfPkg/VirtioNetDxe/SnpInitialize.c | 36 ++++++++++++++++---- 2 files changed, 31 insertions(+), 9 deletions(-) -- 1.8.3.1 _______________________________________________ edk2-devel mailing list edk2-devel@lists.01.org https://lists.01.org/mailman/listinfo/edk2-devel