From 0eebb791b1b8e96be64e9cafb96e93500c0d6163 Mon Sep 17 00:00:00 2001 From: Laszlo Ersek Date: Mar 14 2016 11:50:13 +0000 Subject: OvmfPkg: VirtioNetDxe: adapt virtio-net packet header size to virtio-1.0 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 Cc: Jordan Justen Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Laszlo Ersek --- diff --git a/OvmfPkg/VirtioNetDxe/SnpInitialize.c b/OvmfPkg/VirtioNetDxe/SnpInitialize.c index 38012a0..4942b59 100644 --- a/OvmfPkg/VirtioNetDxe/SnpInitialize.c +++ b/OvmfPkg/VirtioNetDxe/SnpInitialize.c @@ -138,6 +138,7 @@ VirtioNetInitTx ( IN OUT VNET_DEV *Dev ) { + UINTN TxSharedReqSize; UINTN PktIdx; Dev->TxMaxPending = (UINT16) MIN (Dev->TxRing.QueueSize / 2, @@ -149,6 +150,14 @@ VirtioNetInitTx ( 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; @@ -160,7 +169,7 @@ VirtioNetInitTx ( // (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); @@ -174,8 +183,13 @@ VirtioNetInitTx ( // // 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 @@ -223,6 +237,7 @@ VirtioNetInitRx ( ) { EFI_STATUS Status; + UINTN VirtioNetReqSize; UINTN RxBufSize; UINT16 RxAlwaysPending; UINTN PktIdx; @@ -230,12 +245,20 @@ VirtioNetInitRx ( 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); // @@ -280,14 +303,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].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; } diff --git a/OvmfPkg/VirtioNetDxe/VirtioNet.h b/OvmfPkg/VirtioNetDxe/VirtioNet.h index 2d3f3d8..7bd8790 100644 --- a/OvmfPkg/VirtioNetDxe/VirtioNet.h +++ b/OvmfPkg/VirtioNetDxe/VirtioNet.h @@ -17,7 +17,7 @@ #ifndef _VIRTIO_NET_DXE_H_ #define _VIRTIO_NET_DXE_H_ -#include +#include #include #include #include @@ -89,7 +89,7 @@ typedef struct { 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;